当最初调用一个函数时,被调用的第一个函数中的第一个this
引用父对象foo
,但是在第一个函数this
所调用的后续函数中引用窗口对象?
var foo = (function Obj(){
var t = this;
return {
getThis: getThis,
getSecondThis: getSecondThis
};
function getThis(){
console.log(this);
console.log(t);
getSecondThis()
return false;
}
function getSecondThis(){
console.log(this);
console.log(t);
return false;
}
})();
foo.getThis();
如果我将来电从getSecondThis()
更改为this.getSecondThis()
,那么this
中的getSecondThis()
会引用父对象foo
,请参阅下面的代码
var foo = (function Obj(){
var t = this;
return {
getThis: getThis,
getSecondThis: getSecondThis
};
function getThis(){
console.log(this);
console.log(t);
this.getSecondThis() //line edited
return false;
}
function getSecondThis(){
console.log(this);
console.log(t);
return false;
}
})();
foo.getThis();
getSecondThis()
在父对象foo
的范围内,但在第二次调用时未指定this
时会返回窗口。
答案 0 :(得分:2)
它只是JS绑定调用上下文的方式:JS绑定上下文(this
引用)ad-hoc。含义:取决于调用的方式,位置和方式,this
将引用不同的对象
我在here, and in the linked answers found on the bottom
基本上,函数是第一类对象,这意味着,与任何值一样,您可以将函数分配给多个变量/属性。当然,如果将一个函数赋值给一个对象(作为一个属性),那么该函数通常被称为一个方法,并且您希望this
指向拥有该方法的对象。登记/>
但是,正如Pointy在评论中指出的:一个对象不能拥有另一个对象。对象可以由另一个对象的一个或多个属性引用。
JS会设置this
来引用拥有该函数的对象。但是,如果您随后将对象分配给变量,那么让this
指向同一个对象是没有意义的。想想你将函数作为函数参数传递的情况(jQuery中的回调等)。您可能希望this
引用新上下文(当然是jQ事件处理程序中的情况!)。
如果没有提供上下文,JS遗憾地默认this
对全局对象的引用。
您可以使用Function.prototype.bind
调用将绑定函数显式绑定到给定的上下文。
如果您要为单个调用指定上下文,可以使用Function.prototype.call(context, arg1, arg2);
或Function.prototype.apply(context, [args]);
大多数大型项目(例如jQ等工具包)通过利用闭包范围来解决这个问题。例如,使用模块模式是控制上下文的常用且简单的方法。 I've explained this, too,附有图表来说明发生了什么:)
一些示例/谜题使这更容易理解或更有趣:
var obj = (function()
{//function scope
'use strict';//this will be null, instead of global, omit this and this can be window
var obj = {},
funcOne = function()
{
console.log(this, obj, this === obj);
funcTwo(this);
obj.funcTwo();
obj.funcTwo(this);
obj.funcTwo(obj);
},
funcTwo = function(that)
{
console.log(this, obj, this === obj, this === that, that === obj);
};
obj.funcOne = funcOne;
obj.funcTwo = funcTwo;
return obj;//is assigned to the outer var
}());
obj.funcOne();
//output:
//- first logs itself twice, then true
//then calls made in funcOne:
funcTwo()
console.log(this, obj, this === obj, this === that, that === obj);
//- this: undefined (omit 'use strict' and it'll be window), obj,
// this === obj => false, this === that => false, that === obj => true
obj.funcTwo();
console.log(this, obj, this === obj, this === that, that === obj);
//logs obj twice, because obj.funcTwo means the context === obj
//this === obj is true (of course)
//that is undefined, so this === that and that === obj are false
//lastly
obj.funcTwo(this);
obj.funcTwo(obj);
你应该能够解决这个问题。您知道正在执行funcOne
的上下文,并且您知道调用funcTwo
作为obj
经验法则
我对写这篇文章犹豫不决,因为它远非准确,而是8/10个案例。假设没有代码通过bind
,call
和apply
干预上下文,您可以使用此技巧计算出上下文:
someObject.someMethod();
/\ ||
|===this===|
//another object:
var obj2 = {
borrowed: someObject.someMethod,
myOwn: function()
{
this.borrowed();
}
};
obj2.myOwn();//this === obj2 (as explained above),
\\
\==> this.borrowed === obj2.borrowed
\\
\==> ~= someObject.someMethod.call(obj2);//function is executed in context of obj2
//simple vars
var alias = someObject.someMethod;//assign to var
alias();//no owner to be seen?
||
?<==|
//non-strict mode:
[window.]alias();
/\ implied ||
|| ||
|==<this>===|
//strict mode
alias.call(undefined);//context is undefined