为何使用Object.assign实现的clone方法运行异常?
问题原因与修复方案
你遇到的问题核心是类字段形式的箭头函数会被绑定到创建它的实例,而且会作为实例的可枚举属性被Object.assign复制。具体执行逻辑如下:
- 创建
test1时,它的clone箭头函数会把this固定绑定到test1本身。 - 调用
test1.clone()生成test2时,Object.assign(cloned, this)会把test1的所有属性(包括绑定了test1的clone方法)全部复制给test2。 - 当你调用
test2.clone()生成test3时,这个clone方法里的this依然指向test1,所以最终复制的是test1的anotherVal(值为2),而非test2的3。
修复方案1:将clone改为原型方法(推荐)
把箭头函数形式的clone改成类的原型方法,这样它不会作为实例属性被Object.assign复制,且this会动态绑定到调用该方法的实例:
class TestCloneable { constructor(someVal) { if (someVal) { this.someVal = someVal; } } clone() { // 改用原型方法,去掉箭头函数 const cloned = new TestCloneable(this.someVal); Object.assign(cloned, this); return cloned; } }
修复方案2:复制时排除clone方法
如果一定要保留类字段的箭头函数写法,可以在复制时过滤掉clone属性,避免旧的绑定关系被传递:
class TestCloneable { constructor(someVal) { if (someVal) { this.someVal = someVal; } } clone = () => { const cloned = new TestCloneable(this.someVal); // 解构排除clone方法,只复制其他属性 const { clone, ...restProps } = this; Object.assign(cloned, restProps); return cloned; }; }
修复方案3:仅复制实例的非方法属性
更严谨的方式是只复制实例自身的非方法属性,彻底避免方法被意外复制:
class TestCloneable { constructor(someVal) { if (someVal) { this.someVal = someVal; } } clone = () => { const cloned = new TestCloneable(this.someVal); // 遍历实例自身所有属性,仅复制非方法类型的属性 Object.getOwnPropertyNames(this).forEach(propName => { if (typeof this[propName] !== 'function') { cloned[propName] = this[propName]; } }); return cloned; }; }
内容的提问来源于stack exchange,提问作者Jez
相关产品推荐
相关产品推荐

