【问题标题】:How can I achieve object encapsulation using EcmaScript 6 classes?如何使用 EcmaScript 6 类实现对象封装?
【发布时间】: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 中定义方法。

标签: javascript ecmascript-6


【解决方案1】:

替换

new Promise(resolve => resolve(instanceES6)).then(instanceES6.doSomething);

new Promise(resolve => resolve(instanceES6)).then(_ => _.doSomething());

它更短,并且可以使用可用的工具实现您想要的。

如果是,正如您在 cmets 中提到的那样,对于您的偏好来说太脆弱了,您可以将 .then 替换为自定义函数,并从原型中获取函数,检查实例是否具有它(通过使用 function.name反向查找的属性 + 引用身份检查),然后在实例上调用它。基本上将运行时类型检查添加到 Promise 链中。

由于 javascript 没有像 java8 这样的方法引用 :: 运算符,我们必须为此原型命名:

class SomethingES6 {
  ...
}

const SomethingClass = SomethingES6.prototype

...

new Promise(...).checkedThen(SomethingClass.doSomething);

.checkedThen 是带有类型检查的自定义函数。由于扩展内置函数是不好的做法,因此也可以先将 Promise 子类化,或者通过将自定义导入到当前范围中来在功能上组合它:

then(then(new Promise(...), SomethingClass.doSomething), SomethingClass.doSomethingElse)

【讨论】:

  • 在我看来,这是一个不存在的问题的糟糕解决方案。
  • 我提出的第一个建议就是使用 lambda。除此之外的一切都更像是一个“如果你仍然坚持”的答案。
猜你喜欢
  • 2016-09-14
  • 2018-03-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-24
  • 2014-07-23
  • 2016-08-23
  • 1970-01-01
  • 2011-03-24
相关资源
最近更新 更多