You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用Object.assign无法将类实例方法赋值给任意对象?

问题:类实例方法无法通过Object.assign复制到对象?
var foo = {};

class bar {
  fiddle() {
    alert('boo');
  }
} 

Object.assign(foo, new bar());

foo.fiddle(); 

这段代码运行时报错:foo.fiddle is not a function,为什么会这样?

实际场景中,我需要把类的fiddle方法复制到另一类的已有实例中,试过类似otherInstance['fiddle'] = bar['fiddle']的写法,但不可行。

我注意到普通对象的方法可以通过Object.assign正常复制:

let x = {a: y => y * 2}
let z = Object.assign({}, x)
console.log(z.a(5)); // 10

简化版:

let calculator = {double: y => y * 2}
let clone = Object.assign({}, calculator)
alert(clone.double(5)); // 10

修改版:

let calculator = {double: y => y * 2}
let clone = {}
Object.assign(clone, calculator)
alert(clone.double(5)); // 10

推测问题和原型机制有关,但不确定具体原因。

更新1

目前我把类改成普通对象暂时解决了问题:

class foo {
  foodle() {
    console.log('1')
  }
}

const bar = {
  fiddle: () => {
    console.log('2');
  }
}

var test = new foo();
var test2 = Object.create(bar);

Object.assign(test, bar);

test.foodle(); // 1
test.fiddle(); // 2

但我更希望全程用类开发组件,有没有恢复类写法的方案?

更新2

我发现这种写法是可行的:

var foo = {}

class bar {
  fiddle() {
    alert('boo');
  }
} 

var barInstance = new bar();

foo['fiddle'] = barInstance['fiddle'];

foo.fiddle(); // boo

解答

核心原因:类方法存储在原型链上,而非实例自身

ES6类中定义的方法(比如bar里的fiddle)默认挂载在类的原型对象(bar.prototype)上,并不是直接存在于类实例(new bar())自身的属性中。

而Object.assign()仅复制源对象自身的可枚举属性,不会遍历原型链上的属性。所以当你用Object.assign(foo, new bar())时,new bar()实例自身没有fiddle属性,自然不会复制到foo里,也就出现了foo.fiddle is not a function的报错。

对比普通对象的情况:普通对象里定义的方法是直接作为对象自身属性存在的,所以Object.assign可以正常复制。

针对类场景的解决方案

方案1:直接从原型上获取方法赋值

既然方法在原型上,你可以直接从类的原型对象或者实例的原型链上拿到方法,再赋值给目标对象:

var foo = {};
class bar {
  fiddle() {
    alert('boo');
  }
}

// 方式1:从类的原型上取
foo.fiddle = bar.prototype.fiddle;
foo.fiddle(); // 正常弹出'boo'

// 方式2:从实例的原型链上取
const barInstance = new bar();
foo.fiddle = barInstance.__proto__.fiddle;
foo.fiddle(); // 同样有效

方案2:批量复制原型上的方法

如果需要批量复制类原型上的所有方法,可以遍历原型对象的属性手动赋值:

var foo = {};
class bar {
  fiddle() {
    alert('boo');
  }
  anotherMethod() {
    console.log('another');
  }
}

// 遍历bar原型上的所有自有属性,跳过constructor
Object.getOwnPropertyNames(bar.prototype).forEach(key => {
  if (key !== 'constructor') {
    foo[key] = bar.prototype[key];
  }
});

foo.fiddle(); // 'boo'
foo.anotherMethod(); // 'another'

方案3:修改目标对象的原型链(适合组件继承场景)

如果你的需求是让目标实例拥有类的所有方法,还可以直接修改目标对象的原型链,实现原型继承:

class foo {
  foodle() {
    console.log('1');
  }
}

class bar {
  fiddle() {
    console.log('2');
  }
}

const test = new foo();
// 让test的原型继承bar的原型,同时保留原foo的原型
Object.setPrototypeOf(test, Object.create(bar.prototype));
Object.setPrototypeOf(test.__proto__, foo.prototype);

test.foodle(); // 1
test.fiddle(); // 2

这种方式符合原型继承逻辑,不会重复复制方法,适合组件复用场景。

不推荐方案:将方法定义为实例自身属性

如果一定要让Object.assign直接复制,可以把方法定义在类的构造函数里,让方法成为实例自身属性:

class bar {
  constructor() {
    this.fiddle = () => {
      alert('boo');
    }
  }
}

var foo = {};
Object.assign(foo, new bar());
foo.fiddle(); // 正常运行

但这种方式会让每个实例都创建一份方法副本,浪费内存,违背类的原型复用设计,不推荐在组件开发中使用。


内容的提问来源于stack exchange,提问作者BLAZORLOVER

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 21:05:37