Prototype: Deep Scope of "This" to Access Instance's Scope

this inside of a nested prototype not pointing to instance

"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.

Javascript, get this from prototype function own field

It's a very bad idea to do so, as it leads to very strange behaviour in some cases, but it's possible:

var Model = function(x) { this.x = x };

Object.defineProperty(Model.prototype, 'a', (function() {
var lastSelf;
function get() { return lastSelf.x }
get.on = function () { return lastSelf.x * 2 };
return { get() { lastSelf=this; return get } };
})());

var m = new Model(17);
console.log(m.a(), m.a.on());

Is it possible to nest functions in an object in a prototype and access the base object?

Turn MyNamespace into a getter and store a reference to the parent:

function Namespace(parent) {
return {
parent,
/* Your functions here */
};
}

Object.defineProperty(HTMLElement.prototype, "namespace", {
get() { return Namespace(this); },
});

console.log(
document.body.namespace.parent === document.body // true
);

Accesing `this` value when the prototype contains an object?

The fundamental problem in your code is that you have only one history object shared between all instances of Foo. You must make it one history per instance. A solution would be this:

function FooHistory(foo){ this._foo = foo;}FooHistory.prototype.back = function() {  if (this._foo._current === undefined) {    return alert("this._foo._current is undefined");  }  this._foo._current--; };
function Foo() { this._current = -1; this.history = new FooHistory(this);}var f = new Foo();f.history.back();

Using 'this' within nested Prototype sub-objects

Whenever you have a call of the form foo.bar(), this inside bar will refer to foo. Unless you bind the the function to a specific value with .bind, or use the new "arrow" functions in ES6.

So one solution could be to bind the methods to the specific instance. However, the instance doesn't exist until you call the constructor function. That means you have to create subObjectX inside the constructor:

function MyObject(argument1, argument2) {
this.property1 = argument1;
this.property2 = argument2;

this.subObject1 = {
method1: function(){
return this.property1;
}.bind(this)
};

this.subObject2 = {
method1: function(){
return this.property2;
}.bind(this)
};
}

Or using the new ES6 arrow functions; these take this from the context in which they're created (unlike normal functions):

// ES6 only!
function MyObject(argument1, argument2) {
this.property1 = argument1;
this.property2 = argument2;

this.subObject1 = {
method1: () => {
return this.property1;
}
};

this.subObject2 = {
method1: () => {
return this.property2;
}
};
}

That means that every instance has it's own copy of the sub-object.

If you want to define the methods on the prototype though, you always have to pass the receiver via .call or .apply:

foo.subObject1.method1.call(foo);

in which case there is not much benefit of assigning it to the prototype at all, and you could just have a simple function that accept the object (method1(foo)).

Way to provide this to the global scope?

I think it should be

API.prototype.request = API.prototype.debounce(API.prototype.makeRequest, 1000, 2)

You have neither an instance (this) nor an options object at the time of creating the method. Those are supplied to the debounced function, where they are stored and then (possibly later) used to call the supplied function.

Btw, it probably makes no sense to place debounce on the prototype of your API - it's a generic helper method, not an instance method. Also notice that when you debounce() the prototype method, all of your calls will be globally debounced. If you want to have one queue per instance of your API, you should better do

function API() {
// in the constructor:
this.request = Helpers.debounce(this.makeRequest);
}
API.prototype.makeRequest = function() { … };
// no prototype .request() method

Organize prototype javascript while perserving object reference and inheritance

You could make Controls a class of it's own:

var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..

var Carousel = function () {
this.controls = new Controls(this);
};
// ..

This doesn't allow you to override the implementation of Controls though. With more dependency injection you'd get something like:

var Controls = function (controllable_object) {
this.ref = controllable_object;
};
Controls.prototype.next = function () {
this.ref.foo();
}
// ..

var Carousel = function () {
this.controllers = [];
};
Carousel.prototype.addController = function (controller) {
this.controllers.push(controller);
};
// ..

var carousel = new Carousel();
carousel.addController(new Controls(carousel));

Javascript prototype chain vs scope chain

In which stage is prototype object aka Foo.prototype created? When the interpreter loads Foo to global scope?

Yes, the prototype object is created when the Foo function is created.

In which lexical scope is its reference stored? (since there's no such ref in visualiser)

In none at all. It's stored only in a property of Foo.

Should foo and bar share the method speak() which belongs to Foo.prototype rather than owning their own copies as shown in visualiser?

Yes. It seems like that visualiser was built for Python and does not support prototype links at all.

Are prototype chain and scope chain unrelated? For example, when foo.speak() is called, first we trace scope chain to get value of foo, then prototype chain to get speak()?

Yes, yes.

Notice however that the visualiser you found does not display the scope chain, it only does display the call stack, and does very bad at visualising lexical scope and closures correctly.



Related Topics



Leave a reply



Submit