我认为我对JavaScript中的this
对象有一个合理的理解。在处理对象,回调以及事件和处理程序时,我从远古时代就没有遇到过任何问题。然而,现在一切都发生了变化。
我爱上了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
指向第一种情况下的窗口对象,但在其他情况下,它不应该指向窗口对象。我在返回之前尝试在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对象的作用域链。 created(和全局对象)。现在,无法对Activation / Variable对象进行垃圾收集,因为globalVar引用的函数对象的执行需要将整个作用域链从其[[scope]]属性添加到为每次调用创建的执行上下文的作用域中。它
所以我需要做的是简化而不是复杂化:
function fromThisFunc()
{
console.log(this);
}
function makeClosure(funcRef)
{
//some code here
return funcRef;
}
这应该有效,对吧?
PS:除了Alnitak的回答,我会这么做,但特别感谢Felix Kling的所有耐心和信息。
答案 0 :(得分:4)
一打电话:
return func(par);
您正在创建一个新范围(具有自己的this
),在这种情况下,因为您没有指定一个对象,通常是this === window
或未定义模式。被调用函数不会继承调用范围内的this
。
为此设置值的方法是:
myobj.func(par); // this === myobj
或
func.call(myobj, ...) // this === myobj
还有:
答案 1 :(得分:1)
this
的值仅取决于您是将函数作为方法还是作为函数调用。
如果将其称为方法,this
将是该方法所属的对象:
obj.myFunction();
如果您将其称为函数,this
将是window
对象:
myFunction();
请注意,即使您在属于对象的方法中,仍然必须使用方法语法调用对象中的其他方法,否则它们将被称为函数:
this.myOtherFunction();
如果在变量中放置方法引用,则将其从对象中分离,并将其作为函数调用:
var f = obj.myFunction;
f();
call
和apply
方法用于将函数作为方法调用,即使它不是对象中的方法(或者它是不同对象中的方法):
myFunction.call(obj);