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 t
It becomes clear when you print the object and the reference to the function:
console.log(obj); // Prints -> Class {property: 1, method: function}
console.log(refToMethod);
// Prints
// function () {
// return this.property;
// }
In the context of the obj
, what is this
? It is the Class
object, that has an attribute called property
.
And what is this
in the context of the refToMethod
? It is the window
object. Thats why your assert failed the first time and it is true the second time. When you declare:
var property = 1;
You are actually declaring an attribute to the window
object.
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
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;
Because you only assigned the function method
to the refToMethod
. When it runs the context is window
.