闭包中的 "this" 关键字

3

我看过很多例子,但似乎无法让一些示例代码正常工作。

请看以下代码:

var test = (function(){
    var t = "test";
    return {
        alertT: function(){ 
            alert(t);
        }
    }
}());

我有一个在window.load事件上的函数,代码如下:

test.alertT();

一切都正常运行。但是,当我尝试在alertT中的alert()中明确设置t的上下文时,我只得到了undefined。

我已经尝试过:

var that = this;
alert(that.t); //undefined

我尝试过:

        return {
            that: this,
            alertT: function(){ 
                alert(that.t); // undefined!
            }
        }

我尝试过以下方法:

var test = (function(){
    var t = "test";
    var myObj = this;
    return {
        alertT: function(){ 
            alert(myObj.t); // undefined!
        }
    }
}());

我缺少什么?我需要能够显式地为回调等设置上下文。我也看到了一些例子(https://dev59.com/tHRC5IYBdhLWcg3wS_AF


为什么你想要显式地设置上下文?你的例子并没有真正展示出来。你要么需要将上下文传递到alertT函数中,要么就需要使用bind方法将函数绑定到你选择的上下文。 - Jakob
这个例子被简化了,以便更容易阅读。我想能够明确地访问闭合的变量,目的是将其传递给另一个传入的函数。 - hackerhasid
3个回答

1

t不在'this'的范围内。t是该方法的本地变量。因此,您需要在某个地方执行

this.t = whatever

...

这是我正在编写的一个应用程序的真实案例

var scope = this;

cells.forEach(function(cell, index) {
            var given = cell.get('given');

            var value = cell.get('value'),
                            valueAsString = '%@'.fmt(value);


             var rowValues = scope.getRowForIndex(index);
            ...
}

forEach函数内的作用域是我遍历的数组'cells'的作用域。由于我希望在调用作用域中执行操作,所以使用了一个闭包...


True。但这也可能是一个坏主意。如果“this”是该方法中的全局对象,则会创建一个全局变量。 - Jakob
但是由于这是一个闭包,如果我只引用t,我会得到封闭的t,因为函数本身不包含任何t变量。我真的很想知道如何在方法内显式地引用封闭的t。 - hackerhasid
@jakob,完全正确。看起来 OP 只是想了解闭包中作用域的工作原理,这只是一个例子。 - hvgotcodes
statichippo:你自己说了。通过内部函数本身没有任何t,你将得到封闭的t。没有明确的方法来做到这一点。在JavaScript中,“this”与C#和Java等语言非常不同。 - Jakob
Jakob -- 没有明确的方法来做这件事吗?那真的很烦人! - hackerhasid
@statichippo:有点像 :) 但那真的没必要。我已经为您编写了一个答案。 - Jakob

1

t只是外部匿名函数(因此也是内部匿名函数)范围内的普通变量。它不是对象上的属性,因此您可以在不引用thisthatthe_other的情况下设置它。

var test = (function(){
    var t = "test";
    return {
        alertT: function(){ 
            alert(t);
        },
        setT: function (new_value) {
            t = new_value;
        }
    }
}());
test.alertT();
test.setT('hello, world');
test.alertT();

您正在使用的语法是 JS 中创建类似于私有变量的常规模式。

直到看到你的答案,我才明白statichippo在问什么。我猜他认为“this”是指包含闭包变量的作用域?解释得很好。我的建议是除非你写类似于OO的代码,其中“this”指的是被操作的对象,否则不要使用“this”,这个例子可以很容易地改变。但正如你所提到的,这个模块模式给你真正的私有变量(这使得调试更加困难)。 - Ruan Mendes

0
在C#和Java中,可以像这样做:
public class MyClass {
    private int x;

    public void DoSomething(int x) {
        int a = this.x;
        int b = x;
    }
}

变量a和b将具有来自不同x的值,因为一个是类的x,另一个是方法的x。
现在,想象一下如果您不能使用“this”来明确地引用类的x。那么你就必须执行以下操作:
public class MyClass {
    private int classX;

    public void DoSomething(int x) {
        int a = classX;
        int b = x;
    }
}

这在 JavaScript 中是一个常见的情况。至少在你所描述的情况下是如此。通过使用 applycall 方法,您可以更改函数执行的上下文,但您永远无法区分具有相同名称但不同作用域的变量。您只需要为其使用不同的名称。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接