【问题标题】:Is it possible to undo Object.assign?是否可以撤消 Object.assign?
【发布时间】:2015-04-05 22:11:31
【问题描述】:

我想使用Object.assign 临时用新方法“升级”一个对象,然后在我用完这些方法后删除它们。举个例子就明白了:

假设我们有一个可以计算数组平均值的 mixin:

var ArrayUtilMixin = {
  avg() {
    let sum = this.reduce( (prev, v) => {return prev + v}, 0);
    return sum / this.length;
  }
};

我们的客户端代码是这样使用的:

let myArr = [0,3,2,4,88];
// now I am in a context where I want to average this array, 
// so I dynamically add the ability with Object.assign
Object.assign(myArr, ArrayUtilMixin);
let avg = myArr.avg();
// do some stuff here with the average
// now we're done, we want declutter the myArr object
// and remove the no longer needed avg() method

Object.unassign(myArr, ArrayUtilMixin);  // <-- CAN WE DO THIS SOMEHOW?

有没有办法做到这一点?如果不是,我是否使用了我真正想要的错误语言功能——在运行时动态添加和删除对象方法的能力,具体取决于上下文。

【问题讨论】:

  • 您可以简单地遍历ArrayUtilMixin 的属性并将它们从myArr 中删除。这仅在分配ArrayUtilMixin 不会覆盖 myArr 的任何属性时才有效。另一种有趣的方法是将ArrayUtilMixin 插入myArr 的原型链。但这可能不适用于原生对象。

标签: ecmascript-6


【解决方案1】:

有没有办法做到这一点?

有一些,但我认为它们都不是你想做的:

  • 使用Object.assign,然后使用delete 新属性

    Object.unassign = function(o, mixin) {
        for (var p in mixin)
            delete o[p]; // deletes own properties only, so don't fear
        return o;
    }
    

    当然,当您覆盖了自己的方法/属性时,这将无法正常工作。

  • 更改要扩展的对象的原型链

    function extend(o, mixin) {
        var m = Object.assign({}, mixin);
        Object.setPrototypeOf(m, Object.getPrototypeOf(o));
        Object.setPrototypeOf(o, m);
        return o;
    }
    function unextend(o) {
        Object.setPrototypeOf(o, Object.getPrototypeOf(Object.getPrototypeOf(o)));
        return o;
    }
    

    这种方法的优点是自己的属性保持自己的属性,因此对象上的分配将照常工作。有一些语言支持这种模式(并将其与多重继承结合起来),但我不确定它的实际效果如何。当然,在 JavaScript 中修改原型链是一个非常糟糕的主意。

  • 添加到原型链

    function extended(o, mixin) {
        return Object.assign(Object.create(o), mixin);
    }
    

    这将创建一个具有从实际对象继承的 mixin 方法的新对象。您只需丢弃临时的“未扩展”,然后再次使用旧的(我猜这不完全是您想到的使用模式?) - 您可以通过将旧的存储在属性中并“展开”来隐藏这一事实" 带有unextend() 函数。

    当然,这种简单而有效的模式的缺点是对临时对象的赋值不起作用。他们会创建新的、自己的属性而不是修改实际的对象,并且一旦你“取消扩展”就会被丢弃。这对您的 avg 方法无关紧要,甚至可以用于某些 mixin,但您可能不希望这样做。

如果不是,我是否使用了错误的语言功能

这很可能没有语言功能。

对于这种情况,最常见的建议是构造一个包装对象(例如,围绕 DOM 对象),它充当用户和实际对象之间的代理。包装器的 API 与被包装对象的 API 完全不同;这不是一个简单的“扩展”。

【讨论】:

  • “当然,在 JavaScript 中修改原型链是一个非常糟糕的主意。” ——为什么这么糟糕?特别是在你给出的例子中?谢谢。
  • “有一些语言支持这种模式(并将其与多重继承结合起来)”——最好的例子是什么?
  • @Jonah: Io 做到了,我认为 Self 或 NewtonScript 也是。
猜你喜欢
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 2022-10-07
  • 2013-02-20
  • 2016-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多