2

I know that if I add a function to an constructors prototype that it will then be available to every object that uses the constructor. And I know that if you add a function as an (object literal I think it's called?) that you would have to access it as a property of the constructor itself. (Difference between adding function to prototype and object literal in javascript).

But what if you declare the new function as 'this.xxx()' within the constructor. How is that any different from declaring a property on the prototype?

My guess is that declaring the function object on the prototype would result in delegation (and only one copy of that function would exist). Vs with 'this', every constructed object would have its own copy of the function.

Is that correct?

function A () {
}

A.prototype.printNum = function () {
    console.log('hi');
}

x = new A ();
x.printNum(); // hi

function B () {
    this.printNum = function () {
        console.log('hi');
    }
}

y = new B ();
y.printNum(); // hi
Community
  • 1
  • 1
Zach Smith
  • 8,458
  • 13
  • 59
  • 133

3 Answers3

2

You are correct.

function A() {}
A.prototype.printNum = function() {};

function B() {
  this.printNum = function() {};
}

var a1 = new A();
var a2 = new A();
console.log(a1.printNum == a2.printNum); // true

var b1 = new B();
var b2 = new B();
console.log(b1.printNum == b2.printNum); // false

In the first case, there is one instance of the function implementation printNum. In the second case, each instance of B has its own function printNum.

Having many functions uses more memory and the object creation is more expensive, but prototype lookups can become a performance problem as well (according to some people, I'd still prefer them).


There is another difference: Many libraries use object.hasOwnProperty() to determine whether a property "is part of" an object. object.hasOwnProperty() returns true if the property is defined on the object itself instead of being inherited.

var a = new A();
cosole.log(a.hasOwnProperty('printNum')); // false

var b = new B();
console.log(b.hasOwnProperty('printNum')); // true

For example, JSON.stringify uses this to check which properties should be included in its output. This does not really matter as we are talking about functions (which will be ignored by JSON.stringify), but let's use this example:

function C() {}
C.prototype.myvar = "Hello world!";

function D() { this.myvar = "Hello world!"; }

var c = new C();
var d = new D();
console.log(JSON.stringify(c)); // {}
console.log(JSON.stringify(d)); // {"myvar":"Hello world!"}

Before ES5, it was pretty difficult to make variables "final" (Java) / "readonly" (C#) in JavaScript. The second approach allows to do so:

function C(finalVariable) {
  this.getMyVariable = function() { return finalVariable };
}

I do not say that this is good style or should be used in practice (it is not even safe as getMyVariable may be overwritten as well), it is just a fact: Using this function instantiation allows to access variables from the constructor without exposing them to other functions through object properties.

Tobias
  • 7,723
  • 1
  • 27
  • 44
  • Good answer. However, the performance (both memory and execution time) concerns are overstated. In the vast majority of applications, it will simply not be an issue.The priority should be clarity and writability and readabilty and maintainability of code, as well as the issue you touched on, which is that methods declared on the instance in the constructor can access private variables (including constructor parameters as you showed). –  Sep 13 '15 at 17:31
1

Your intuition is correct, it's very easy to check for yourself by checking whether the function references are the same or not. Just add these lines to your sample code:

var x2 = new A();
var y2 = new B();

y.printNum === y2.printNum; //will return false
x.printNum === x2.printNum; //will return true

So indeed, when the function is on the prototype, the two instance object will share the reference. (Because when the printNum property lookup fails on x and x2 it will be delegated to the same prototype object, A.prototype. In case of y and y2, both instances have an own printNum property, so the prototype chain is not even consulted.)

(An object literal, btw, is a mostly unrelated subject, see MDN for a definition of it.)

doldt
  • 4,466
  • 3
  • 21
  • 36
0

The difference is when you call the constructor (using new) you execute what is inside, so, if you add to declare a bunch of time new B() you will have a performance issue.

romuleald
  • 1,406
  • 16
  • 31