object.setprototypeof() 动态修改对象的[[prototype]]内部槽,改变其原型链上一级,影响属性查找和方法继承,但不修改构造函数prototype属性,也不影响其他实例。

JavaScript 中不能直接用 setPrototypeOf “修改原型对象本身”的继承关系,而是通过它**动态更改某个对象的 [[Prototype]] 内部槽**,从而改变该对象在原型链上的上一级。这会影响属性查找和方法继承,但要注意它不改变构造函数的 prototype 属性,也不影响已创建实例的原始原型链(除非你对那个实例调用)。
setPrototypeOf 的基本用法
Object.setPrototypeOf(obj, prototype) 接收两个参数:目标对象 obj 和新的原型对象 prototype(可以是 null 或一个对象)。成功时返回 obj,失败(如目标不可扩展且无法修改原型)则抛错。
- 它等价于非标准但曾广泛使用的
obj.__proto__ = prototype,但更规范、更推荐 - 只能修改**对象实例**的原型,不能修改函数的
prototype属性(那是另一个独立的属性) - 频繁调用会影响引擎优化(如内联缓存),生产环境慎用
修改实例的继承关系(常见场景)
假设你有一个普通对象,想让它临时拥有某个类的方法:
const animal = { species: 'unknown' };
const dogProto = { bark() { return 'Woof!'; } };
Object.setPrototypeOf(animal, dogProto);
console.log(animal.bark()); // 'Woof!'
console.log(animal.__proto__ === dogProto); // true
这里 animal 原本原型是 Object.prototype,调用后其 [[Prototype]] 指向 dogProto,因此能访问 bark。
Java JDK 25 来自 OpenJDK 官方归档,版本为 JDK 25,本条下载地址已指向官方 Windows x64 zip 安装包直链,适合调试旧项目或兼容旧版 Java 运行环境。
注意:不会影响构造函数或已有其他实例
修改一个实例的原型,**不会**改变它的构造函数,也不会波及同源的其他实例:
function Cat() {}
Cat.prototype.meow = () => 'Meow';
const cat1 = new Cat();
const cat2 = new Cat();
Object.setPrototypeOf(cat1, { purr() { return 'Purr~'; } });
console.log(cat1.purr()); // ✅ 'Purr~'
console.log(cat1.meow()); // ❌ undefined(原 Cat.prototype 不再在链上)
console.log(cat2.meow()); // ✅ 'Meow'(cat2 原型未变)
console.log(cat1.constructor); // 仍是 Cat(constructor 是从原 prototype 继承来的,现在找不到了,所以会继续向上找到 Object.prototype.constructor)
替代方案:更安全的继承建模方式
若目标是设计可复用的继承结构,优先使用以下方式,而非运行时改原型:
-
class+extends:语义清晰,静态可分析 -
Object.create(proto):创建时就指定原型,避免后期修改 - 组合(composition):用属性委托代替原型继承,更可控
例如用 Object.create 替代:
const dogMethods = { bark() { return 'Woof!'; } };
const myDog = Object.create(dogMethods); // 从创建之初就设定原型
myDog.name = 'Buddy';
不复杂但容易忽略:setPrototypeOf 改的是“谁的爸爸”,不是“谁的孩子”;它动的是实例的隐式链接,不是类的蓝图。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










