如何在JavaScript中使用箭头功能克隆对象?

时间:2018-08-20 23:43:28

标签: javascript scope clone deep-copy

我有以下JavaScript代码段:

RotaID, 
PayperodID,
EmployeeID

RotaID
Start_dt
Finish_dt

我想知道可以用什么来代替class Foo { constructor() { this.b = 1; this.getB = () => { return this.b; }; } } const normalFoo = new Foo(); const clonedFoo = magicClone(normalFoo); clonedFoo.b = 5; console.log(clonedFoo instanceof Foo); // should be true console.log(clonedFoo.getB()); // should be 5 以获得期望的结果(例如,尊重箭头功能绑定的克隆)。

我可以接受各种可怕的黑客手段,并且我对大多数时候都可以使用的解决方案也可以,只要在这种情况下可以使用。这主要是为了我的教育:)


请不要以重复的形式关闭此问题-克隆对象已被问过很多次,但我找不到能做到这一点的单个答案。 magicClone,lodash的Object.assign,jQuery的克隆等都无法处理这种情况。

3 个答案:

答案 0 :(得分:1)

因此,这里的主要挑战是您有一个箭头功能,该功能被分配为Foo实例上的属性。由于箭头函数从其封闭的上下文继承它们的this并且一旦创建就无法反弹,这是让getB引用克隆的b的唯一方法字段是重新创建该箭头功能。这意味着您必须以某种方式调用Foo的构造函数,以便使用正确的上下文重新创建arrow函数。

也就是说,这个magicClone实现可以解决此示例的问题:

function magicClone(obj) {
    // Manually create new instance of whatever `obj` is by invoking its constructor:
    const newInstance = new obj.__proto__.constructor()

    // Assign to the new instance all the non-function properties of `obj`.
    Object.assign(newInstance, JSON.parse(JSON.stringify(obj)));

    return newInstance;
}

但是,这种方法的主要缺点是,如果obj的构造函数需要任何参数,则无法知道它们应该是什么。因此,这种方法依赖于您的示例Foo类具有无参数构造函数的事实。但是,如果您可以保持这种局限性,那么它将为您带来正确的输出:

class Foo {
    constructor() {
        this.b = 1;
        this.getB = () => { return this.b; };
    }
}

function magicClone(obj) {
    const newInstance = new obj.__proto__.constructor()
    Object.assign(newInstance, JSON.parse(JSON.stringify(obj)));
    return newInstance;
}

const normalFoo = new Foo();
normalFoo.otherProp = "must stay the same";

const clonedFoo = magicClone(normalFoo);
clonedFoo.b = 5;

console.log(clonedFoo instanceof Foo); // should be true
console.log(clonedFoo.getB()); // should be 5
console.log(clonedFoo.otherProp)

答案 1 :(得分:0)

您不能“重新绑定”箭头功能。将始终在定义它的上下文中调用它。只需使用常规功能即可。

来自ECMAScript 2015 Spec

  

在ArrowFunction中对参数,super,this或new.target的任何引用都必须在词汇包围的环境中解析为绑定。通常,这将是立即封闭函数的函数环境。

答案 2 :(得分:0)

从根本上讲,克隆功能是不可能的。它可能是一个闭包,我们既无法知道也无法克隆它所关闭的内容。 (箭头函数关闭其var marioToDraw = marioright; function paint() { if(background.loadOK) { paper.drawImage(background.imagen, 0, 0); } //draw the selected Mario paper.drawImage(marioToDraw.imagen, x, y); } //inside the switch statement switch(evento.keyCode) { case keys.RIGHT: marioToDraw = marioright; x = x + movement; break; case keys.LEFT: marioToDraw = marioleft; x = x - movement; break; default: console.log("A different key was pressed!"); } paint(); 值只是这种情况的一种特殊情况。)

您最好的选择是使用实例实现克隆协议:

this