【发布时间】:2015-02-10 02:17:31
【问题描述】:
由于 Javascript 中的方法很容易被反弹,一些(很多?)开发人员求助于使用 JS 的词法作用域来实现对象封装(即,独立于方法当前绑定的对象的私有对象状态)。在使用这样的 Promise 时,我发现这特别方便:
function Something() {
const that = this; // optional
that.state = 0;
this.doSomething = function() {
console.log(that.state++);
};
return this;
}
const instance = new Something;
new Promise(resolve => resolve(instance)).then(instance.doSomething);
//output: 0
不幸的是,这似乎与当前的 Ecmascript 6 类草案不兼容。这段代码:
class SomethingES6 {
constructor(){
this.state = 0;
}
doSomething(){
console.log(this.state++);
}
}
const instanceES6 = new SomethingES6;
new Promise(resolve => resolve(instanceES6)).then(instanceES6.doSomething);
因为 doSomething 方法在执行时未绑定到 instanceES6 而引发。有没有办法实现类似于在前一个 sn-p 中利用 "that" 的词法范围时所暴露的行为?
我想要一个在定义类时强制执行此行为的解决方案 - bluebird(和其他)的 Promise.bind 不是解决方案!就我个人而言,我想要一个适用于节点的解决方案,但当然,更可取的是通用解决方案。
【问题讨论】:
-
bind绝对是一个解决方案。预绑定很烦人。您似乎也将承诺视为回调的包装版本,但事实并非如此;试试Promise.resolve(instanceES6).then(instance => instance.doSomething()),例如.. -
一个重要说明:
instance.doSomething--- 当这个函数引用被 promise 调用时,它不是一个instance实例。 -
@minitech:你的提议创建了很多样板代码,特别是对于长承诺链。和所有样板一样,它非常脆弱:我(或其他人)忘记或意外删除了“解析/绑定”,我花了半个小时追踪一个奇怪的错误。这就是我喜欢“预绑定”版本的原因。但是,我的个人偏好并不重要(你的也不重要)。我只是好奇新标准是否打破了过去有效的东西。
-
您的问题标题严重误导。您可以通过多种方式“实现对象封装”,包括使用 ES6 类——这就是类为生的方式。您真正的意思是“ES6 类真的意味着我不能通过构造函数中的本地副本在其中引用
this来继续使用我的预绑定方法技巧吗?”从恕我直言开始,这从来都不是一个特别有趣的模式。一方面,它将方法放置在每个实例中,而不是原型中。 -
您所要求的与 ES6 类无关。在第一种情况下,您在构造函数中声明方法,在原型中的第二种情况。当然,这些会产生不同的结果(因为词法范围),但这与 ES6 类无关。如果你愿意,你也可以在
constructor中定义方法。