Skip to content Skip to sidebar Skip to footer

"this" Inside Of A Nested Prototype Not Pointing To Instance

Given: var x = function () { }; x.prototype = { y: { z: function () { console.log(this); } } }; var foo = new x(); foo.y.z(); Why is this log

Solution 1:

"Why is this logged in the console as y instead of x..."

Because that's how JavaScript works. The this value is set as the object from which the method was invoked. Generally you should keep objects off of the .prototype. They're going to be shared among all instances created using the constructor.


"...and how is that possible given y is a literal object without a constructor?"

It's easy. The this value is not tied to any constructor. It's a dynamic value that is set based on how you invoke a function or method.


There are utilities that let you manually override the natural value that this is set to in an invocation. Using the .call or .apply methods of the Function.prototype to invoke the method is one example

var foo = new x();
foo.y.z.call(foo);

Now this in the z method will be the foo object, because we manually set it by passing it as the first argument to .call.

The .call method sees that it was called as a method of the z method, and so it invokes z for you, but sets the this value of z to whatever you provided as the first argument... in this case the foo object.


But generally you won't use objects as values of the .prototype. The reason is that all instances created from the constructor get an implicit reference to the .prototype of the constructor, so updates to any objects on properties of the .prototype will be observed from all instances.


Solution 2:

To make this work, you need y to return the enclosing this.

var x = function () {};
Object.defineProperty(x.prototype, "y", { get: function() { return this; } })
x.prototype.y.z = function () { console.log(this); }

var foo = new x();
foo.y.z(); // x

Whatever is to the left of the . on z() is this. In your question, y returns the object literal: {z:function(){...}}.


Solution 3:

var y=Object.create({z: function () { console.log(this); }});
var x=Object.create(y);
y.z();
x.z();

You may use Object.create to create an object instead of using constructor.


Post a Comment for ""this" Inside Of A Nested Prototype Not Pointing To Instance"