【问题标题】:Access local variable of function inside callback在回调中访问函数的局部变量
【发布时间】:2017-03-25 15:23:03
【问题描述】:

如果我在函数中创建回调,我可以让该回调访问该函数中的局部变量吗?

Obj.prototype.outerFunc = function() 
{
    var x = 0;
    var callback = this.innerFunc;
    callback();
}

Obj.prototype.innerFunc = function()
{
    x++;
}

x自然不在innerFunc的范围内,如果自己调用会报错。但是如果我从outerFunc 调用它,我可以扩展innerFunc's 范围以访问x吗?

编辑:应该提到我不想将参数传递给函数或制作 x 和 Obj 的实例。我更希望将innerFunc 视为在outerFunc 本地声明。类似于下面可以做的:

Obj.prototype.outerFunc = function()
{
    var x = 0;
    var callback = function() {
        x++;
    }
    callback(); // works
}

【问题讨论】:

  • 唯一的方法是outerFuncx 放在共享范围内。全局范围在所有函数之间共享。但是没有办法直接影响被调用者的范围。基本上你所追求的是动态范围。 JavaScript 和大多数语言都有词法范围

标签: javascript scope callback


【解决方案1】:

是的:这正是函数参数的用途。它们允许您将值从一个范围传递到另一个范围。

Obj.prototype.outerFunc = function() 
{
    var x = 0;
    var callback = this.innerFunc;
    x = callback(x);
}

Obj.prototype.innerFunc = function(x)
{
    x++;
    return x;
}

请注意,该值被发送到另一个函数,而不是变量。所以你需要返回值并赋值才能使用它。

【讨论】:

  • 应该提到但我试图避免将 x 作为参数传入(请参阅我对原始问题所做的编辑)
  • @sookie 这正是函数应该避免的。
【解决方案2】:

如果您使用原型,只需设置一个实例属性:

// constructor
var Obj = function () {}

Obj.prototype.outerFunc = function() 
{
   this.x = 0;
   var callback = this.innerFunc.bind(this);
   callback();
}

Obj.prototype.innerFunc = function()
{
   this.x++;
}

var instance = new Obj()
instance.outerFunc()
console.log(instance.x) // returns 1

编辑:但@lonesomeday 的答案是一个更好的解决方案,因为它采用了一种更实用的方法来避免副作用:)

【讨论】:

  • 对不起,应该提到,但我实际上是想避免让 x 成为 Obj 的实例(请参阅我对原始问题所做的编辑)
【解决方案3】:

这样做的首选方法是将 x 分配给对象的范围,然后所有函数都可以通过 this.x 访问它

Obj.prototype.outerFunc = function() 
{
    this.x= 0; // set x to zero
    this.innerFunc();

}

Obj.prototype.innerFunc = function(x)
{
    this.x++;
    return this.x;
}

【讨论】:

  • 谢谢。我实际上是在尝试避免使 x 成为 Obj 的实例(请参阅我对原始问题所做的编辑)
  • 如果您可以在 outerFunc 中添加原型,那么 x 将是可访问的,或者如果您可以使 x 成为对象之外的全局对象。
【解决方案4】:

在不知道为什么不想传递参数的情况下,这有点难以解决;如果您只想拥有特定的函数签名,也许高阶函数可能会有所帮助?

Obj.prototype.outerFunc = function() 
{
    var x = 0;
    var callback = this.innerFunc(x);
    callback();
}

Obj.prototype.innerFunc = function(x)
{
    return function () { /* use x in here */ };
}

这样你就有了两个功能,一个在另一个里面。外层取参数,内层可以访问传给外层的变量。

这当然只为您提供了示例中演示的一半:您可以访问局部变量但不能修改它。

【讨论】:

    【解决方案5】:

    在任何情况下,在 OOP 上下文或其他情况下,您都不能从函数外部访问任何函数的内部变量。

    唯一的例外是在函数 B 中定义并从该函数 B 返回的函数 A 继续可以访问函数 B 中的变量——闭包的基本概念。

    我不知道你为什么不想使用实例变量。这就是他们的目的——跨方法共享数据。我不知道您为什么不想将值传入或传出——这就是参数和返回值的用途。

    我可以扩展innerFunc 的范围以访问x吗?

    不,你不能,不管那是什么意思。 JS中没有这个概念。

    最接近您可能想要做的事情是在构造函数中定义变量:

    function Obj() {
      var x = 0;
    
      this.outerFunc = function() {
        var callback = this.innerFunc;
        callback();
      };
    
      this.innerFunc = function() {
        x++;
      }
    }
    

    但是,这不会按原样工作,因为this.innerFunc 缺少其上下文。因此,您需要编写

    var callback = () => this.innerFunc();
    

    但是,您为什么要这样做而不只是写this.innerFunc(),这是一个谜。

    【讨论】: