JavaScript闭包和这个对象

时间:2012-05-09 08:01:08

标签: javascript object closures this

我认为我对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的所有耐心和信息。

2 个答案:

答案 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();

callapply方法用于将函数作为方法调用,即使它不是对象中的方法(或者它是不同对象中的方法):

myFunction.call(obj);