Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 375
Artūras Avatar asked Apr 18 '14 13:04

Artūras


2 Answers

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;
like image 121
Ian Clark Avatar answered Sep 30 '22 18:09

Ian Clark


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

like image 28
Vlad Bezden Avatar answered Sep 30 '22 17:09

Vlad Bezden