What are the downsides of defining functions on prototype this way?

function, javascript, prototype

Solution

Let's actually compare both the ways and see which one is faster: http://jsperf.com/traditional-oop-vs-derek-s-oop-variant

As you can see your method is much slower than the traditional method. The reasons are:

- Your constructor is doing more stuff than required. Hence if you create multiple instances then the extra cost of creating an instance adds up.

- As @Alxandr mentioned you're creating a new anonymous function for `method` every time you create a new instance for no good reason. It'll only be useful once after which it'll be a waste of processing power.

- You're calling a function to check whether the `prototype` of the constructor has a given method or not, and to add the method to the `prototype` if it doesn't. This seems unnecessary. You don't need to create a function to do this for you. IMHO the function call is just additional overhead.

Since you asked for criticism:

I'm aware that augmenting `Object.prototype` isn't considered a good practice. But other than that are there any downsides with this approach?

Beside being terribly slow your approach also suffers from:

- Being difficult to understand. You may find this approach intuitive. However a person reading your code would surely wonder what the function `this.method` does. They would need to read the definition of `Object.prototype.method` to fully comprehend your code.

- Being unintuitive. As I mentioned before it makes no sense to be defining `prototype` properties inside the constructor. It'll only be needed once after which it'll just become additional baggage. It's best to keep the constructor logic and the `prototype` properties separate.

- It may lead to unexpected behavior. As @basilikum pointed out if you never call the constructor then the `prototype` properties will never be set. This may lead to problems when you attempt to access a property on the `prototype`. For example, when inheriting properties from the `prototype` no properties will be inherited until the base constructor is called.

I believe your goal is to encapsulate both the constructor and the `prototype` properties into a single entity:

However I was trying to come up with a way to define a function on a prototype without separating the function definition with the constructor.

Is there an easy way to do this? Let's see, JavaScript is a prototypal object oriented language. Hence we should focus more on the `prototype` instead of the constructor.

The above diagram was taken from the following answer: https://stackoverflow.com/a/8096017/783743

This diagram shows us:

- Every constructor has a property called `prototype` which points to the prototype object of the constructor function.

- Every prototype has a property called `constructor` which points to the constructor function of the prototype object.

- We create an instance from a constructor function. However the instance actually inherits from the `prototype`, not the constructor.

This is very useful information. Traditionally we've always created a constructor function first and then we've set its `prototype` properties. However this information shows us that we may create a prototype object first and then define the `constructor` property on it instead.

For example, traditionally we may write:

function Shape() {
    this.x = 0;
    this.y = 0;
}

Shape.prototype.move = function(x, y) {
    this.x += x;
    this.y += y;
};

However using our newfound knowledge we may write the same thing as:

var shape = {
    constructor: function () {
        this.x = 0;
        this.y = 0;
    },
    move: function (x, y) {
        this.x += x;
        this.y += y;
    }
};

The information contained in both these examples is the same. However we need a little additional scaffolding to make the second example work. In particular we need to do:

var Shape = shape.constructor;
Shape.prototype = shape;

This is not a big issue. We simply create a function to do this for us:

function defclass(prototype) {
    var constructor = prototype.constructor;
    constructor.prototype = prototype;
    return constructor;
}

Now we can define `Shape` as follows:

var Shape = defclass({
    constructor: function () {
        this.x = 0;
        this.y = 0;
    },
    move: function (x, y) {
        this.x += x;
        this.y += y;
    }
});

As you can see encapsulation is easy to achieve in JavaScript. All you need to do is think sideways. Inheritance however is a different issue. You need to do a little more work to achieve inheritance.

Hope this helped.

Problem

Usually people write code like this: ``` function Shape() { this.x = 0; this.y = 0; } Shape.prototype.move = function(x, y) { this.x += x; this.y += y; } ``` However I was trying to come up with a way to define a function on a prototype without separating the function definition with the constructor. Here is what I got: ``` Object.prototype.method = function(name, func) { if (typeof(this.constructor.prototype[name]) === 'undefined') { this.constructor.prototype[name] = func } } ``` This allows you to do something like: ``` function Shape() { this.x = 0; this.y = 0; this.method('move', function(x, y) { this.x += x; this.y += y; }) } ``` And also no matter how many times you create a shape, the function will only be defined once. I'm aware that augmenting `Object.prototype` isn't considered a good practice. But other than that are there any downsides with this approach? EDIT: Johan brought up a good point; I should have made `method` not enumerable. Here is the revised version: ``` Object.defineProperty(Object.prototype, 'method', { value: function(name, func) { if (typeof(this.constructor.prototype[name]) === 'undefined') { this.constructor.prototype[name] = func } }, enumerable: false }) ```

Original source

Related problems