Javascript lost context when assigned to other variable

房东的猫 提交于 2019-11-27 05:21:19

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;
Vlad Bezden

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

Because you only assigned the function method to the refToMethod. When it runs the context is window.

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.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!