5

我以为我对thisJavaScript 中的对象有一个合理的理解。在处理对象、回调以及事件和处理程序时,自古以来我就没有遇到过问题。然而现在,一切都变了。

我已经完全爱上了 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 提供的所有耐心和信息。

4

2 回答 2

4

只要你打电话:

return func(par);

您正在创建一个新范围(具有自己的this),在这种情况下,因为您没有指定对象,this === window通常或在严格模式下未定义。被调用的函数不会继承this调用范围内的任何内容。

为此设置值的方法

myobj.func(par);  // this === myobj

或者

func.call(myobj, ...)  // this === myobj

还有:

于 2012-05-09T08:07:02.740 回答
1

的值this仅取决于您将函数作为方法调用还是作为函数调用。

如果将其作为方法调用,this将是该方法所属的对象:

obj.myFunction();

如果您将其作为函数调用,this则将是window对象:

myFunction();

请注意,即使你在一个属于某个对象的方法中,你仍然必须使用方法语法调用该对象中的其他方法,否则它们将被作为函数调用:

this.myOtherFunction();

如果你把一个方法引用放在一个变量中,你会把它从对象中分离出来,它会作为一个函数被调用:

var f = obj.myFunction;
f();

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

myFunction.call(obj);
于 2012-05-09T08:19:59.120 回答