【问题标题】:Augment all objects with another class properties/methods用另一个类属性/方法扩充所有对象
【发布时间】:2018-05-16 13:32:04
【问题描述】:

假设我有两个班级

class Point {
}

class EditablePoint extends Point {
  // list of additional properties and methods
}

function edit(editablePoint) {
  //
}

let point = new Point();
edit(point);

如何使用其他类的方法/属性来扩充所有对象?

任何prototype hack 都不适合我。似乎我无法解决这个问题,而不是重新创建对象或手动分配类的附加属性或使用循环。我想要一些干净的解决方案。

免责声明:这看起来像是我同意的反模式,但是我有大量 Points 数组,只有在非常罕见的情况下我才需要编辑它们并我想在不引入任何复制的情况下就地执行此操作,因为数组非常庞大。

为什么我不喜欢让所有点都具有可编辑的属性并希望将它们放在原型上:

  • 每个对象实例都会变大,这是我最不想要的
  • 它无法与代码阅读器很好地通信

【问题讨论】:

  • 在我看来,就像你试图用一个马鞍骑两匹马。因此,您希望所有Point 实例都具有EditablePoint 的方法您不想更改Point 的原型分配Point 实例的方法?
  • 问题陈述不清楚,代码没有解释你想要做什么。什么是“其他对象”? 我有两个班级 - 其中哪个是您提到的“另一个班级”? 任何原型黑客对我都不起作用。 - 你到底尝试了什么,什么不起作用?
  • @MátéSafranka 我没有说明我不想改变原型。我想要。我只是不知道在对象已经创建后该怎么做
  • 对不起,我误会了。答案即将到来。
  • @estus 问题已明确说明,不是吗? “如何使用其他类方法/属性来扩充所有对象?”

标签: javascript ecmascript-6 es6-class


【解决方案1】:

你要问的是技术上可行

let pointProto = Point.prototype;
let editProto = EditablePoint.prototype;

for (let memberName in editProto) {
    if (typeof editProto[memberName] === 'function'
        && !(memberName in pointProto)) {
        pointProto[memberName] = editProto[memberName];
    }
}

这将实现您所描述的:Point 类的所有实例现在将具有与 EditablePoint 实例相同的方法(!(memberName in pointProto) 子句确保我们不会覆盖已定义的方法) .

但是,正如您自己所说,这是一个 大量 反模式,因为此时您正在模糊这两个类之间的界限,以至于不清楚为什么它们甚至单独存在课程;看到Points 的数组被当作EditablePoints 使用是一种 100% 肯定的方式来迷惑正在阅读您的代码的任何人。如果您认为自己需要这样的东西,最好重新考虑您的模型结构。

【讨论】:

    【解决方案2】:

    您可以使用Object.assign 添加属性和setPrototypeOf 通过将EditablePoint 的原型设置为Point 的原型来添加方法,但是由于EditablePoint 继承自Point,因此您仍然拥有Point方法。

    class Point {
      constructor() {
        this.point = true;
      }
      foo() {
        console.log('foo')
      }
    }
    
    class EditablePoint extends Point {
      constructor() {
        super();
        this.editable = true;
      }
      bar() {
        console.log('bar')
      }
    }
    
    function edit(editablePoint) {
      Object.assign(editablePoint, new EditablePoint);
      Object.setPrototypeOf(editablePoint, EditablePoint.prototype)
    }
    
    let point = new Point();
    edit(point);
    
    console.log(point)
    point.foo();
    point.bar();

    【讨论】:

      【解决方案3】:

      我认为你不应该创建一个继承自Point 并具有编辑所需的所有方法的EditablePoint 类。相反,使用组合而不是继承,并创建一个类

      class PointEditor {
          constructor(point) {
              this.point = point;
              …
          }
          …
      }
      

      具有编辑与编辑器关联的点所需的所有方法。这样,您可以为数组中要编辑的点实例化尽可能少/尽可能多的 PointEditors,而无需更改数组中点的创建方式。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-10-09
        • 2015-01-07
        • 2021-01-10
        • 1970-01-01
        • 1970-01-01
        • 2020-03-10
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多