繁体   English   中英

如何在JavaScript中使用箭头函数克隆对象?

[英]How to clone an object with an arrow function in JavaScript?

我有这段JavaScript代码:

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以获得所需的结果(例如,一个尊重箭头功能绑定的克隆)。

我对任何类型的可怕黑客都很好,只要他们在这种情况下工作,我也可以使用大多数时间都有效的解决方案。 这主要是为了我的启发:)


请不要将此问题作为副本关闭 - 克隆对象已被多次询问,但我找不到单一的答案。 Object.assign ,lodash的cloneDeep ,jQuery的克隆等都不处理这种情况。

所以这里的主要挑战是你有一个箭头函数,它被指定为你的Foo实例的属性。 由于箭头功能继承this从他们的包围下, 他们不能反弹一旦建立 ,只有这样才能有getB引用克隆的b字段是重新创建箭头功能。 这意味着你必须以某种方式调用Foo的构造函数,以便使用正确的上下文重新创建箭头函数。

也就是说,这个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) 

克隆函数根本不可能。 它可能是一个封闭,我们既不知道也不能克隆它所关闭的东西。 (箭头函数关闭它们的this值只是一个特例)。

您最好的选择是实例实施克隆协议:

class Foo {
    constructor() {
        this.b = 1;
        this.getB = () => { return this.b; };
    }
    clone() {
        return new Foo // usually passing the current instance's state as arguments
    }
}
function magicClone(o) {
    if (Object(o) !== o) return o; // primitive value
    if (typeof o.clone == "function") return o.clone(); // if available use it
    return Object.assign(Object.create(Object.getPrototypeOf(o)), o); // shallow copy
}

const normalFoo = new Foo();
const clonedFoo = magicClone(normalFoo);

你不能“重新绑定”箭头功能。 它将始终使用定义它的上下文进行调用。 只需使用正常功能。

来自ECMAScript 2015规范

对ArrowFunction中的arguments,super,this或new.target的任何引用都必须解析为词法封闭环境中的绑定。 通常,这将是直接封闭函数的函数环境。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM