在JavaScript中,每个对象都有一个隐藏的内部属性[[Prototype]],指向它的原型对象,对象可以从原型对象上继承属性和方法。当我们需要修改对象的原型时,有多种不同的实现方式,不同方式的适用场景和特性也存在差异。

直接修改构造函数的prototype属性
如果对象是通过构造函数创建的,那么修改该构造函数的prototype属性,会影响所有由这个构造函数创建的实例对象的原型。这种方式适合需要批量修改某一类对象原型的场景。
示例代码如下:
// 定义构造函数
function Person(name) {
this.name = name;
}
// 创建实例
const person1 = new Person('张三');
// 修改构造函数的prototype,添加新方法
Person.prototype.sayHello = function() {
console.log(`你好,我是${this.name}`);
};
// 已有的实例也能访问到新增的方法
person1.sayHello(); // 输出:你好,我是张三
// 新创建的实例同样可以访问
const person2 = new Person('李四');
person2.sayHello(); // 输出:你好,我是李四
需要注意的是,这种方式只会影响修改之后创建的实例,以及修改之前创建的、本身没有同名属性的实例。如果实例本身已经存在和原型上同名的属性,那么会优先访问实例自身的属性,不会去原型上查找。
使用Object.setPrototypeOf方法
ES6引入了Object.setPrototypeOf方法,可以直接修改一个已有对象的原型,不需要通过构造函数。这个方法接收两个参数,第一个是要修改原型的对象,第二个是新的原型对象。
示例代码如下:
// 定义两个原型对象
const protoA = {
methodA() {
console.log('这是protoA的方法');
}
};
const protoB = {
methodB() {
console.log('这是protoB的方法');
}
};
// 创建对象,初始原型为protoA
const obj = Object.create(protoA);
obj.methodA(); // 输出:这是protoA的方法
// 修改obj的原型为protoB
Object.setPrototypeOf(obj, protoB);
// 现在obj可以访问protoB上的方法,无法访问protoA的方法
obj.methodB(); // 输出:这是protoB的方法
obj.methodA(); // 输出:Uncaught TypeError: obj.methodA is not a function
这种方式可以动态修改单个对象的原型,但是频繁使用Object.setPrototypeOf修改对象原型会导致JavaScript引擎的优化失效,带来性能问题,所以不建议在性能敏感的场景中使用。
通过Object.create创建新对象指定原型
如果不需要修改已有对象的原型,而是需要创建一个原型是指定对象的新对象,可以使用Object.create方法。这个方法会创建一个新对象,并且把传入的参数作为新对象的原型。
示例代码如下:
// 定义原型对象
const baseProto = {
add(a, b) {
return a + b;
}
};
// 创建新对象,原型为baseProto
const newObj = Object.create(baseProto);
console.log(newObj.add(1, 2)); // 输出:3
console.log(Object.getPrototypeOf(newObj) === baseProto); // 输出:true
如果需要基于已有对象创建新对象并修改原型,可以结合已有对象的属性和新的原型来实现,这种方式不会修改原对象的原型,只会生成一个新的对象。
不同修改方式的对比
我们可以通过下面的表格来对比几种修改对象原型方式的特点:
| 修改方式 | 适用场景 | 影响范围 | 性能影响 |
|---|---|---|---|
| 修改构造函数prototype | 批量修改某类实例的原型 | 所有该构造函数的实例 | 较小,引擎可优化 |
| Object.setPrototypeOf | 修改单个已有对象的原型 | 仅当前被修改的对象 | 较大,可能导致优化失效 |
| Object.create | 创建新对象时指定原型 | 仅新创建的对象 | 较小,引擎可优化 |
注意事项
- 修改对象原型时要避免循环原型链,比如让对象A的原型指向对象B,同时对象B的原型又指向对象A,这会导致属性查找时出现无限循环,引发错误。
- 如果对象的原型被修改,那么原型链上的属性查找顺序会立刻发生变化,已经执行的代码如果依赖之前的原型链,可能会出现不符合预期的结果。
- 在ES5及之前的浏览器中,
Object.setPrototypeOf可能不被支持,如果需要兼容旧环境,可以使用obj.__proto__ = newProto的写法,但是__proto__并不是标准属性,不建议在生产环境中使用。
查看对象原型的方法
如果需要验证对象的原型是否修改成功,可以使用Object.getPrototypeOf方法获取对象的原型,示例代码如下:
function Foo() {}
const foo = new Foo();
const newProto = { bar: 1 };
Object.setPrototypeOf(foo, newProto);
console.log(Object.getPrototypeOf(foo) === newProto); // 输出:true
console.log(foo.bar); // 输出:1
JavaScript对象原型prototypeObject_setPrototypeOf修改时间:2026-07-14 00:15:28