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 loadsFoo
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
andbar
share the methodspeak()
which belongs toFoo.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 offoo
, then prototype chain to getspeak()
?
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
JavaScript Accessing Inner Dom of Svg
How to Check If a Number Is Between Two Values
Check If Jquery Has Been Loaded, Then Load It If False
What Is "Callback Hell" and How and Why Does Rx Solve It
Indirect Function Call in JavaScript
Deep Copy in Es6 Using the Spread Syntax
Eslint Parsing Error: Unexpected Token
How to Set the Prototype of a JavaScript Object That Has Already Been Instantiated
Convert Time Interval Given in Seconds into More Human Readable Form
Firebase Query Methods Startat() Taking Case Sensitive Parameters
How to Copy JavaScript Object to New Variable Not by Reference
JavaScript to Sort Contents of Select Element
How to Access a Child's State in React
App.Settings - the Angular Way
How to Replace Captured Groups Only
Is There Any Difference Between Declared and Defined Variable