Javascript lost context when assigned to other variable
Why in javascript if you reference objects method to some variable it loses that objects context. Can't find any link with explanation what happens under the hood. Except this one which states: ‘this’ refers to the object which ‘owns’ the method which doesn't seam to be true.
var Class = function() {
this.property = 1
}
Class.prototype.method = function() {
return this.property;
}
var obj = new Class();
console.log(obj.method() === 1);
var refToMethod = obj.method; // why refToMethod 'this' is window
console.log(refToMethod() !== 1) // why this is true?
var property = 1;
console.log(refToMethod() === 1)
Solution 1:
It depends on how a function is called. If a function is not referenced through being an attribute of an object (e.g. refToMethod
) then it will be assigned the "Global context" which is window
. However, when a function is an attribute of object (e.g. obj.method
), we refer to it as a method, and it is implicitly assigned the context of it's parent object.
JavaScript's context is unlike many languages in that you can override it easily using either .call()
or .apply()
. Furthermore, ECMAScript 5 introduced a new .bind()
method to allow you to create copies of methods which are always bound to the same context. See MDN for more.
var obj = new Class();
obj.method(); // 1;
var unbound = obj.method;
unbound(); // undefined;
// Call and Apply setting the context to obj.
unbound.apply(obj); // 1
unbound.call(obj); // 1;
// ECMAScript 5's bind
var bound = unbound.bind(obj);
bound(); // 1;
Solution 2:
From Douglas Crockford's book JavaScript: The Good Parts
The this parameter is very important in object oriented programming, and its value is determined by the invocation pattern. There are four patterns of invocation in JavaScript: the method invocation pattern, the function invocation pattern, the constructor invocation pattern, and the apply invocation pattern. The patterns differ in how the bonus parameter this is initialized
The Method Invocation Pattern
When a function is stored as a property of an object, we call it a method. When a method is invoked, this is bound to that object. If an invocation expression contains a refinement (that is, a . dot expression or[subscript] expression), it is invoked as a method
In your example method invocation pattern is
console.log(obj.method() === 1);
and this in this case is bound to the object "Class" and it works as you expected.
The Function Invocation Pattern
When a function is not the property of an object, then it is invoked as a function:
var sum = add(3, 4); // sum is 7
When a function is invoked with this pattern, this is bound to the global object. This was a mistake in the design of the language. Had the language been designed correctly, when the inner function is invoked, this would still be bound to the this variable of the outer function. A consequence of this error is that a method cannot employ an inner function to help it do its work because the inner function does not share the method’s access to the object as its this is bound to the wrong value
In your case
var refToMethod = obj.method; // why refToMethod 'this' is window
console.log(refToMethod() !== 1) // why this is true?
refToMethod is bound to the global object "window" in this case
You can find more information about this at JavaScript “this” keyword