【发布时间】:2012-05-09 08:01:07
【问题描述】:
我以为我对 JavaScript 中的 this 对象有一个合理的理解。在处理对象、回调以及事件和处理程序时,自古以来我就没有遇到过问题。然而现在,一切都变了。
我已经完全爱上了 JavaScript。纯 JS,即不是 jQuery、prototype.js、dojo……所以自然而然地,我开始使用闭包。不过,在某些情况下,this 让我措手不及。把这个 sn-p 当作一个:
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 在第一种情况下指向窗口对象,但在其他情况下,它不应该。在返回之前,我尝试在 makeClosure 函数中记录this,它确实记录了对象本身,而不是window 对象。但是当使用实际的闭包时,this 又回到了指向窗口对象的状态。为什么?
我唯一能想到的是,通过将anyFunc 函数作为参数传递,我实际上是在传递window.anyFunc。所以我尝试了这个快速修复:
function makeClosure(func)
{
var theFunc = func;
return function(par)
{
theFunc(par);
}
}
有了预期的结果,this 现在指向对象,但再次:为什么?我有一些想法(theFunc 是对本地范围内的函数的引用 [this > private: theFunc]?),但我敢肯定这里有人对 JS 有更多的专业知识,所以我希望从他们那里得到更多的解释或链接到值得一读的文章……
谢谢
更新
Here's a fiddle,可能是我遗漏了一些东西,但这里记录了各种各样的东西;)
编辑/更新 2
The case that confuses me 在这里。
最终编辑
好的,这是一个相当混乱的帖子。所以澄清一下:我所期待的是与此类似的行为:
function makeClosure()
{
function fromThisFunc()
{
console.log(this);
}
return fromThisFunc;
}
var windowContext = makeClosure();
windowContext();
var objectContext = {cls:makeClosure()};
objectContext.cls();
让我印象深刻的是函数anyFunc 没有在正确的范围内声明,因此this 指向了窗口对象。我通过阅读我在网上某处找到的ancient scroll 发现了这一点。
但是发生了一些更复杂的事情,因为现在由 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 提供的所有耐心和信息。
【问题讨论】:
-
我真的没有得到其他答案,除了可以提供一个指向全球闭包解释的链接。本课程是一本优秀的读物,应该消除所有不确定性:ejohn.org/apps/learn
-
问题不在于我没有关闭。导致头痛的原因是我不完全确定
this对象在以我在这里的方式进行闭包时会发生什么 -
我无法重现您描述的行为。我得到
DOMWindow、Object、Object:jsfiddle.net/GErkX,而你的第二个“修复”给了我 3 xDOMWindow:jsfiddle.net/tZXQF -
顺便说一句,这是正确的行为,所以如果它能像你描述的那样工作,我会感到非常惊讶。
-
重新编辑:这里有什么令人困惑的地方?您正在像普通函数 (
func(par)) 一样调用func,因此函数内部this指的是window。这是您的第一个案例,这似乎是您所期望的。
标签: javascript object closures this