保持巴贝尔类为'this`使用`setTimeout`一个成员函数时(Keep babel

2019-09-27 10:52发布

我有一个ES2015类,称之为Foo ,其具有至少两个成员函数, barbaz 。 在bar有一个呼叫setTimeout它的第一个参数是this.baz 。 做工精细了这里,我检查它在调试器,并且this确实涉及到我的类的实例。 (其实因为我使用的是巴贝尔,我结束了一个_this = this替代事先但无论如何,正确的事情被传递到setTimeout证实。)

问题是,当setTimeout回调火灾,它调用正确的函数baz ,但是this里面baz的价值this是指Window代替。 巴别试图做一个_this2 = this之初baz但似乎为时已晚了。

所以,出现在我的问题,在功能之间的某处baz传递,它被调用的时候,它就失去了this范围界定。 我的问题是,我在做什么毛病ES2015还是巴别在这里? 我喜欢这种感觉是,它不应该要求太多应变共同足够的使用情况。 个人而言,我想做到这一点所有Promise ,但由于业务需求,我不能一下子加太多新的东西,JS。

另外,有传递范围的标准成语this ,因为我需要在这里? 看来真的是凌乱和反直觉必须通过一个成员函数的调用对象作为它的参数之一。

下面是引用一个最小的工作示例:

class Foo{
    bar(){
        setTimeout(this.baz, 1000);
    }
    baz(){
        console.log("this message should repeat roughly once per second");
        this.bar();
    }
}

而这里的使用这是一个非常简单的页面上,并显示错误消息沿着我的截图:

编辑:我反对我的问题被标记为重复。 当然,我已经搜查看到setTimeout问这个人之前的问题。 然而,ES2015和class我的问题的基础的方面是相关的,重要的,因为在巴别类的ES2015语法转换改变的明显行为this 。 我的问题是关于是否有另一个ES2015的设计模式来处理这个问题,为什么直观class抽象/封装正被传递一个成员函数作为第一类值破被外部调用。 我获得的最显著的见解是从下方留言,通过@FelixKing我将在这里重复为后代(如果任何人想知道)闪闪发光:

无论autobind类的方法(像在Python)进行了讨论,但最终决定放弃,可能保持一致性与语言的其余部分。 还有一个问题,是否有可能autobind无记忆/性能影响的方法。

Answer 1:

我的问题是,我在做什么毛病ES2015还是巴别在这里?

其实,这是一个预期的JavaScript行为,并涉及到如何this在语言分配。

考虑下面(无ES6,没有通天...)的代码:

var obj = {
   key1: 'value1',
   key2: function() {
     console.log(this);
   }   
}

obj.key2(); //will print obj

var callback = obj.key2; //assigned the function reference to some random variable

callback(); //will print Window/global object

正如你所看到的, this 是调用函数时定义,而不是在它的声明,并取决于它如何被调用。

这正是发生了什么里面setTimeout ,或在接收函数作为参数的函数:

/* fake */
function setTimeout(fnCallback, time) {
    /* wait and when the time comes, call your callback like this: */
    fnCallback(); //'this' will be Window/global
}

“解决办法”:

为了通过所期望的上下文(在上面的例子中),我们可以强制语境:

  1. 使用.bind

     var callback = obj.key2.bind(obj); callback(); //will print obj 
  2. 或使用.call

     var callback = obj.key2; callback.call(obj); //will print obj 

或者,我们可以通过一个anymous功能的从内拨打我们的对象:

setTimeout(function() {
   //here, 'this' is Window/global, because the anonymous function is being called from a callback assignment
   obj.key2(); //will print obj
}, 3000);

在你的榜样

所以,在你的榜样,为了正确设置setTimeout回调,并确保baz()将获得一流的背景下,您可以:

  1. 将其设置为一个回调的情况下绑定功能:

     setTimeout(this.baz.bind(this), 1000); 
  2. 在类的构造函数, bindbaz一次法; 所以,每次它的名字,将被分配类上下文。 像这样:

     class Foo{ constructor() { this.baz = this.baz.bind(this) } bar(){ setTimeout(this.baz, 1000); } baz(){ console.log("this message should repeat roughly once per second"); this.bar(); } } 
  3. 使用arrow functions 。 指定的另一种方式this方面是使用arrow functions ,即,实际上,保证this任务是通过词法范围做(不再在函数调用,但在函数声明)。

     setTimeout(() => this.baz(), 1000); // ^^^^ // 'this' here is your class, will pass your class as 'this' // to the baz() method, due to the dot before 

    不同于:

     setTimeout(function() { this.baz(); }, 1000); // ^^^^ // 'this' here is Window/global, will thrown undefined method 


文章来源: Keep babel class as `this` when using a member function in `setTimeout`