JavaScript中Prototype Shadowing与Prototype Chaining的区别及概念答疑
我来给你把这俩概念掰得明明白白,再配上例子——毕竟刚开始啃JS原型的时候,这俩确实容易绕混!
什么是原型链(Prototype Chaining)?
原型链是JavaScript实现继承的核心底层机制。简单说:每个对象都有一个隐藏的[[Prototype]](可以用Object.getPrototypeOf()访问,老代码里常看到的__proto__是浏览器提供的非标准访问方式),这个原型对象本身也有自己的原型,直到某个对象的原型是null(也就是Object.prototype的原型是null),这就形成了一条链式结构。
当你访问一个对象的属性或方法时,JS会按顺序查找:
- 先在对象自身找有没有这个属性
- 找不到就去它的原型对象里找
- 再找不到就继续往上找原型的原型,直到走到链的尽头(返回
undefined)
举个直观的例子:
// 定义父构造函数 function Animal(name) { this.name = name; } // 在Animal的原型上添加共享方法 Animal.prototype.sayName = function() { console.log(`我的名字是${this.name}`); }; // 定义子构造函数 function Dog(name, breed) { Animal.call(this, name); // 继承实例属性 this.breed = breed; } // 让Dog的原型指向Animal的实例,建立原型链 Dog.prototype = Object.create(Animal.prototype); // 修正constructor指向(不然Dog.prototype.constructor会指向Animal) Dog.prototype.constructor = Dog; // 创建Dog实例 const myDog = new Dog('巴迪', '金毛'); // 访问sayName:myDog自身没有,去Dog.prototype找,没有再去Animal.prototype找,找到了! myDog.sayName(); // 输出:我的名字是巴迪
这里的原型链是:myDog -> Dog.prototype -> Animal.prototype -> Object.prototype -> null
什么是原型遮蔽(Prototype Shadowing)?
原型遮蔽就是当你在对象自身添加了一个和原型链上某个属性同名的属性时,这个自身属性会“盖住”原型链上的同名属性——JS访问这个属性时,会优先取对象自身的,不会再往上走原型链找那个同名的。
还是用上面的例子改一改:
// 给myDog自身添加一个sayName方法 myDog.sayName = function() { console.log(`汪!我是${this.name},一只${this.breed}`); }; // 现在访问sayName,直接取自身的方法,原型链上的Animal.prototype.sayName被遮蔽了 myDog.sayName(); // 输出:汪!我是巴迪,一只金毛 // 如果删掉myDog自身的sayName,又会回到原型链上的方法 delete myDog.sayName; myDog.sayName(); // 又输出:我的名字是巴迪
还有个特殊情况:如果原型链上的属性是getter,你给对象赋值同名属性时,会直接在自身添加属性从而遮蔽原型的getter(除非原型有对应的setter):
const parent = { get name() { return '父对象'; } }; const child = Object.create(parent); console.log(child.name); // 输出:父对象 // 给child赋值name,因为parent没有setter,所以会给child添加自身的name属性,遮蔽原型的getter child.name = '子对象'; console.log(child.name); // 输出:子对象 console.log(Object.hasOwn(child, 'name')); // true,说明child自身确实有这个属性了
二者的核心区别
- 本质不同:
- 原型链是一种属性查找机制/继承结构,是JS对象属性查找的基础路径。
- 原型遮蔽是属性查找过程中的一种现象,是自身属性和原型链属性同名时的优先级覆盖行为。
- 作用不同:
- 原型链让对象可以继承原型上的属性和方法,实现代码复用,是JS继承的核心。
- 原型遮蔽允许我们在实例或子对象上重写原型上的属性/方法,定制化单个对象的行为,同时不影响原型本身(其他实例依然用原型上的版本)。
- 触发条件不同:
- 原型链是默认存在的,只要对象不是
null,就有自己的原型链。 - 原型遮蔽只有当对象自身存在与原型链上同名的属性时才会发生。
- 原型链是默认存在的,只要对象不是
内容的提问来源于stack exchange,提问作者Parimal Padture
相关产品推荐
相关产品推荐

