面试之《原型与原型链》
在 JavaScript 中,原型(Prototype) 和 原型链(Prototype Chain) 是实现对象继承和属性共享的核心机制。以下是详细介绍:
一、原型(Prototype)
-
基本概念
- 每个函数(包括构造函数)都有一个
prototype
属性,指向一个对象,称为原型对象。 - 当使用
new
调用构造函数创建实例时,实例内部会有一个隐藏属性__proto__
(ES6 规范中称为[[Prototype]]
),指向构造函数的原型对象。 - 原型对象的作用是为所有实例共享属性和方法,避免重复定义。
- 每个函数(包括构造函数)都有一个
-
示例
function Person(name) { this.name = name; } // 原型对象添加方法 Person.prototype.sayHello = function() { console.log(`Hello, ${this.name}`); }; const person = new Person("Alice"); console.log(person.__proto__ === Person.prototype); // true person.sayHello(); // Hello, Alice
二、原型链(Prototype Chain)
-
基本概念
- 每个对象(包括原型对象)都有自己的
__proto__
,指向其“父级”原型对象,形成一条链式结构,称为原型链。 - 当访问对象的属性或方法时,JavaScript 会沿着原型链向上查找,直到找到目标属性或到达
null
(终点)。
- 每个对象(包括原型对象)都有自己的
-
原型链结构
Object.prototype ← Function.prototype ← ... ← 自定义原型 ← 实例
- 所有对象的最终原型是
Object.prototype
,它定义了toString()
、valueOf()
等通用方法。 - 函数的原型是
Function.prototype
,而Function.prototype
的原型是Object.prototype
。
- 所有对象的最终原型是
-
示例
const obj = {}; console.log(obj.toString()); // 来自 Object.prototype console.log(obj.hasOwnProperty("toString")); // false(属于原型链)
三、关键特性
-
属性查找规则
- 优先查找对象自身的属性,若不存在则沿原型链向上查找。
- 修改对象自身的属性会直接覆盖原型链中的同名属性。
-
原型链的继承
- 通过修改原型对象,可以实现类似“继承”的效果。例如:
function Animal() {} Animal.prototype.eat = function() { console.log("Eating..."); }; function Dog() {} Dog.prototype = Object.create(Animal.prototype); // Dog 的原型链继承 Animal Dog.prototype.bark = function() { console.log("Woof!"); }; const dog = new Dog(); dog.eat(); // 继承自动物原型 dog.bark(); // 自身方法
- 通过修改原型对象,可以实现类似“继承”的效果。例如:
-
原型链的终点
Object.prototype.__proto__
的值为null
,表示原型链的结束。
四、相关方法
-
isPrototypeOf()
检查一个对象是否是另一个对象的原型:console.log(Animal.prototype.isPrototypeOf(dog)); // true
-
hasOwnProperty()
判断属性是否是对象自身的属性(而非原型链中的属性):console.log(dog.hasOwnProperty("bark")); // true
-
Object.getPrototypeOf()
获取对象的原型(ES6 方法,替代__proto__
):console.log(Object.getPrototypeOf(dog) === Dog.prototype); // true
五、注意事项
- 避免原型链过长:过长的原型链会影响属性查找性能。
- 原型与实例的动态关联:修改原型对象会影响所有后续创建的实例,但已存在的实例不会受影响。
class
语法糖:ES6 的class
本质上仍基于原型链,只是语法糖简化了实现。
总结
- 原型是对象共享属性和方法的基础。
- 原型链通过
__proto__
连接对象,实现属性的继承和查找。 - 理解原型链有助于掌握 JavaScript 的核心机制(如继承、多态),并避免常见错误。