文章目录
一、什么是原型链?
在 JavaScript 中,每个对象都有一个内部属性 [[Prototype]]
,指向另一个对象,这个指向的对象被称为原型(prototype
)。通过原型,子对象可以访问父对象的属性和方法。原型链就是一系列对象通过 prototype
属性连接起来的链条,最终指向 null
。
二、原型链的基本原理
- 每个 JavaScript 对象都有一个
prototype
属性,指向其原型对象。 - 当访问一个对象的属性时,JavaScript 引擎会先查找对象本身,如果找不到,则会顺着
[[Prototype]]
链向上查找,直到找到该属性或者到达链条的末端null
。 - 如果原型链中的每个对象都没有找到该属性或方法,最终返回
undefined
。
三、原型链的构建
- 对象的原型:
- 对于由构造函数创建的对象(如
new Object()
、new Array()
等),它们的原型对象是该构造函数的prototype
属性。 Object
的原型是null
,即原型链的终点。
- 对于由构造函数创建的对象(如
- 构造函数的
prototype
属性:- 每个构造函数都有一个
prototype
属性,这个属性是一个对象,包含了该构造函数创建的实例的默认属性和方法(如constructor
属性)。
- 每个构造函数都有一个
四、原型链的例子
1. 基本示例:构造函数与原型链
function Animal(name) {
this.name = name;
}
Animal.prototype.sayHello = function() {
console.log(`${this.name} says hello!`);
};
const dog = new Animal('Buddy');
dog.sayHello(); // 输出 "Buddy says hello!"
console.log(dog.__proto__ === Animal.prototype); // true
dog
是Animal
构造函数的一个实例。dog
对象没有sayHello
方法,但是它的原型dog.__proto__
指向Animal.prototype
,所以dog
可以访问Animal.prototype
中的方法。dog.__proto__ === Animal.prototype
返回true
,证明dog
的原型链确实指向了Animal.prototype
。
2. 多级原型链
function Animal(name) {
this.name = name;
}
Animal.prototype.sayHello = function() {
console.log(`${this.name} says hello!`);
};
function Dog(name, breed) {
Animal.call(this, name); // 继承 Animal 的属性
this.breed = breed;
}
// 继承 Animal 的方法
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
const myDog = new Dog('Buddy', 'Golden Retriever');
myDog.sayHello(); // 输出 "Buddy says hello!"
console.log(myDog instanceof Dog); // true
console.log(myDog instanceof Animal); // true
Dog
通过Object.create(Animal.prototype)
设置了自己的原型链指向Animal.prototype
,从而继承了Animal
的方法。myDog
可以访问Animal.prototype
中的方法,并且myDog instanceof Dog
和myDog instanceof Animal
都返回true
,说明myDog
既是Dog
的实例,也是Animal
的实例。
3. 原型链的继承与 constructor
function Animal(name) {
this.name = name;
}
function Dog(name, breed) {
Animal.call(this, name);
this.breed = breed;
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog; // 修复 constructor 指向
const myDog = new Dog('Buddy', 'Golden Retriever');
console.log(myDog.constructor); // Dog() 构造函数
- 在上面的代码中,
Dog.prototype.constructor
被设置为Dog
,以修复继承链中的constructor
指向,使得myDog.constructor
返回的是Dog
构造函数。
五、原型链的特点
- 共享属性和方法:
- 原型链的最大特点是,多个实例可以共享原型对象上的方法和属性,而不需要每次创建实例时都重新定义。
- 性能问题:
- 访问原型链上的属性时,性能相对较低,因为 JavaScript 需要逐层查找原型链,直到找到属性或者原型链的末尾。
- 如果有大量的原型链查找,可能会影响性能,因此应尽量避免在原型链上放置频繁访问的属性。
- 原型链的终点是
null
:- 所有对象的原型链最终都会指向
null
,这标志着原型链的结束。
- 所有对象的原型链最终都会指向
六、__proto__
和 prototype
的区别
prototype
是构造函数上的属性,用来为该构造函数创建的对象实例提供原型对象。__proto__
是对象上的属性,指向该对象的原型对象,即该对象的构造函数的prototype
属性。
示例:
function Animal(name) {
this.name = name;
}
const dog = new Animal('Buddy');
console.log(dog.__proto__ === Animal.prototype); // true
console.log(Animal.prototype.__proto__ === Object.prototype); // true
七、总结
- 原型链 是对象和构造函数之间的一个连接机制,它使得对象能够继承构造函数的属性和方法。
- 每个对象都通过
[[Prototype]]
指向其构造函数的prototype
属性,而构造函数的prototype
属性指向其父类的原型对象,最终形成一个链条,链条的尽头是null
。 - 通过原型链,JavaScript 实现了继承的机制,允许对象共享属性和方法。