Use of 'prototype' vs. 'this' in JavaScript?

sw234 picture sw234 · Nov 22, 2008 · Viewed 118.6k times · Source

What's the difference between

var A = function () {
    this.x = function () {
        //do something
    };
};

and

var A = function () { };
A.prototype.x = function () {
    //do something
};

Answer

keparo picture keparo · Nov 22, 2008

The examples have very different outcomes.

Before looking at the differences, the following should be noted:

  • A constructor's prototype provides a way to share methods and values among instances via the instance's private [[Prototype]] property.
  • A function's this is set by how the function is called or by the use of bind (not discussed here). Where a function is called on an object (e.g. myObj.method()) then this within the method references the object. Where this is not set by the call or by the use of bind, it defaults to the global object (window in a browser) or in strict mode, remains undefined.
  • JavaScript is an object-oriented language, i.e. most values are objects, including functions. (Strings, numbers, and booleans are not objects.)

So here are the snippets in question:

var A = function () {
    this.x = function () {
        //do something
    };
};

In this case, variable A is assigned a value that is a reference to a function. When that function is called using A(), the function's this isn't set by the call so it defaults to the global object and the expression this.x is effective window.x. The result is that a reference to the function expression on the right-hand side is assigned to window.x.

In the case of:

var A = function () { };
A.prototype.x = function () {
    //do something
};

something very different occurs. In the first line, variable A is assigned a reference to a function. In JavaScript, all functions objects have a prototype property by default so there is no separate code to create an A.prototype object.

In the second line, A.prototype.x is assigned a reference to a function. This will create an x property if it doesn't exist, or assign a new value if it does. So the difference with the first example in which object's x property is involved in the expression.

Another example is below. It's similar to the first one (and maybe what you meant to ask about):

var A = new function () {
    this.x = function () {
        //do something
    };
};

In this example, the new operator has been added before the function expression so that the function is called as a constructor. When called with new, the function's this is set to reference a new Object whose private [[Prototype]] property is set to reference the constructor's public prototype. So in the assignment statement, the x property will be created on this new object. When called as a constructor, a function returns its this object by default, so there is no need for a separate return this; statement.

To check that A has an x property:

console.log(A.x) // function () {
                 //   //do something
                 // };

This is an uncommon use of new since the only way to reference the constructor is via A.constructor. It would be much more common to do:

var A = function () {
    this.x = function () {
        //do something
    };
};
var a = new A();

Another way of achieving a similar result is to use an immediately invoked function expression:

var A = (function () {
    this.x = function () {
        //do something
    };
}());

In this case, A assigned the return value of calling the function on the right-hand side. Here again, since this is not set in the call, it will reference the global object and this.x is effective window.x. Since the function doesn't return anything, A will have a value of undefined.

These differences between the two approaches also manifest if you're serializing and de-serializing your Javascript objects to/from JSON. Methods defined on an object's prototype are not serialized when you serialize the object, which can be convenient when for example you want to serialize just the data portions of an object, but not it's methods:

var A = function () { 
    this.objectsOwnProperties = "are serialized";
};
A.prototype.prototypeProperties = "are NOT serialized";
var instance = new A();
console.log(instance.prototypeProperties); // "are NOT serialized"
console.log(JSON.stringify(instance)); 
// {"objectsOwnProperties":"are serialized"} 

Related questions:

Sidenote: There may not be any significant memory savings between the two approaches, however using the prototype to share methods and properties will likely use less memory than each instance having its own copy.

JavaScript isn't a low-level language. It may not be very valuable to think of prototyping or other inheritance patterns as a way to explicitly change the way memory is allocated.