我以为我对this
JavaScript 中的对象有一个合理的理解。在处理对象、回调以及事件和处理程序时,自古以来我就没有遇到过问题。然而现在,一切都变了。
我已经完全爱上了 JavaScript。纯 JS,即不是 jQuery、prototype.js、dojo……所以自然而然地,我开始使用闭包。不过,在某些情况下,这this
让我措手不及。以这个片段为例:
function anyFunc(par)
{
//console.log(par);
console.log(this);
}
function makeClosure(func)
{
return function(par)
{
return func(par);
}
}
var close = makeClosure(anyFunc);
close('Foo');
var objWithClosure = {cls:makeClosure(anyFunc),prop:'foobar'};
objWithClosure.cls(objWithClosure.prop);
var scndObj = {prop:'Foobar2'};
scndObj.cls = makeClosure;
scndObj.cls = scndObj.cls(anyFunc);
scndObj.cls(scndObj.prop);
在所有三种情况下,都this
将日志记录为窗口对象。当然,这很容易解决:
function makeClosure(func)
{
return function(par)
{
return func.call(this,par);
}
}
这个修复有效,我把它放在这里是为了避免人们回答这个问题,没有解释我需要知道的:为什么它的行为方式在这里?
确保调用者实际上是闭包所属的对象。我不明白的是:果然,this
在第一种情况下指向窗口对象,但在其他情况下,它不应该。this
我在返回之前尝试登录makeClosure 函数,它确实记录了对象本身,而不是window
对象。但是当实际使用闭包时,this
又是回到指向窗口对象。为什么?
我唯一能想到的是,通过将anyFunc
函数作为参数传递,我实际上是在传递window.anyFunc
. 所以我尝试了这个快速修复:
function makeClosure(func)
{
var theFunc = func;
return function(par)
{
theFunc(par);
}
}
有了预期的结果,this
现在指向对象,但又一次:为什么?我有一些想法(theFunc
是对本地范围内的函数的引用 [ this > private: theFunc
]?),但我敢肯定这里有人对 JS 有更多的专业知识,所以我希望得到一些更多解释或链接到值得阅读的文章...
谢谢
更新
这是一个小提琴,可能是我遗漏了一些东西,但是这里记录了各种各样的东西;)
编辑/更新 2
让我困惑的案例就在这里。
最终编辑
好的,这是一个相当混乱的帖子。所以澄清一下:我所期待的是与此类似的行为:
function makeClosure()
{
function fromThisFunc()
{
console.log(this);
}
return fromThisFunc;
}
var windowContext = makeClosure();
windowContext();
var objectContext = {cls:makeClosure()};
objectContext.cls();
引起我注意的是该函数anyFunc
没有在正确的范围内声明,因此this
指向了窗口对象。我通过阅读我在网上某处找到的古代卷轴发现了这一点。
但是发生了一些更复杂的事情,因为现在由 globalVar 引用的函数对象是使用 [[scope]] 属性创建的,该属性引用了一个范围链,该范围链包含属于创建它的执行上下文的 Activation/Variable 对象(并且全局对象)。现在 Activation/Variable 对象也不能被垃圾回收,因为 globalVar 引用的函数对象的执行需要将整个作用域链从其 [[scope]] 属性添加到为每次调用创建的执行上下文的作用域中它。
所以我需要做的是简化而不是复杂化:
function fromThisFunc()
{
console.log(this);
}
function makeClosure(funcRef)
{
//some code here
return funcRef;
}
那应该有效,对吧?
PS:我会排除 Alnitak 的回答,但特别感谢 Felix Kling 提供的所有耐心和信息。