JavaScript通过原型链实现继承与隔离的协同:属性查找先查实例自身,未命中则沿[[Prototype]]链向上;实例同名属性会遮蔽原型属性,确保数据独立。

JavaScript 通过原型链天然支持属性的“继承”与“隔离”并存——继承靠 [[Prototype]] 链向上查找,隔离靠实例自身属性优先覆盖(属性遮蔽),二者不是对立关系,而是协同工作的底层机制。
继承:属性查找遵循原型链
当访问一个对象的属性时,JS 引擎按以下顺序查找:
- 先在对象自身(
this)上找,命中则返回; - 未命中,则沿
__proto__(即内部[[Prototype]])指向的原型对象继续查找; - 直到找到该属性,或到达
null(原型链终点)为止。
例如:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
function Animal(name) { this.name = name; }
Animal.prototype.speak = function() { return `${this.name} makes a sound`; };
const dog = new Animal('Dog');
console.log(dog.speak()); // ✅ 找到 Animal.prototype.speak
console.log(dog.name); // ✅ 找到自身属性 name
隔离:实例属性优先于原型属性(遮蔽机制)
若实例自身拥有同名属性,它会“遮蔽”(shadow)原型上的同名属性——查找时不会继续往上,从而实现数据隔离。
立即学习“Java免费学习笔记(深入)”;
- 每个实例可独立设置自己的值,不影响其他实例或原型;
- 修改实例属性 ≠ 修改原型属性;
- 删除实例属性后,再次访问同名属性将自动回退到原型上。
例如:
dog.speak = function() { return `${this.name} barks`; };
console.log(dog.speak()); // ✅ 调用实例方法,不走 Animal.prototype
const cat = new Animal('Cat');
console.log(cat.speak()); // ✅ 仍调用 Animal.prototype.speak —— dog 的修改未影响 cat
delete dog.speak;
console.log(dog.speak()); // ✅ 回退到原型方法
关键设计点:构造函数 + 原型组合使用
要兼顾复用(继承)与独立(隔离),常规模式是:
- 在构造函数中初始化**实例独有**的数据(如
this.name,this.id); - 在
prototype上定义**所有实例共享**的方法和默认属性; - 避免在原型上放可变对象(如
prototype.data = []),否则会被所有实例共享修改。
错误示范:
Animal.prototype.hobbies = []; // ❌ 所有实例共用同一个数组
dog.hobbies.push('fetching'); // 影响 cat.hobbies
正确做法:
function Animal(name) {
this.name = name;
this.hobbies = []; // ✅ 每个实例独立初始化
}
现代补充:class 语法只是糖,本质不变
class 写法更清晰,但底层仍是原型链:
class Animal {
constructor(name) { this.name = name; }
speak() { return `${this.name} speaks`; }
}
// 等价于:Animal.prototype.speak = function() { ... }
静态方法、getter/setter、私有字段(#field)等扩展特性,也都在这个原型模型基础上分层构建,不破坏继承与隔离的协作逻辑。

















