在JavaScript中,理解原型(prototype)和原型链(prototype chain)是掌握面向对象编程的关键。下面,我将通过代码演示来帮助您彻底理解这两个概念。
原型(Prototype)
在JavaScript中,每个函数都有一个特殊的属性prototype
,它是一个对象,包含了由该函数创建的所有实例共享的属性和方法。这个对象默认有一个constructor
属性,指向该函数本身。
不管如何创建只要是对象都会有这样的一个内置属性,那么这个对象有什么用呢?
当我们通过引用对象的属性key来获取一个value时,它会触发 [[Get]]的操作
首先检查该对象是否有对应的属性,如果有的话就使用它
如果对象中没有该属性,那么会访问对象[[prototype]]内置属性指向的对象里的属性
示例代码:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${
this.name} and I am ${
this.age} years old.`);
};
const person1 = new Person('Alice', 30);
const person2 = new Person('Bob', 25);
person1.sayHello(); // Hello, my name is Alice and I am 30 years old.
person2.sayHello(); // Hello, my name is Bob and I am 25 years old.
在这个例子中,Person
函数的prototype
属性被赋予了一个新的对象,该对象有一个sayHello
方法。通过new Person(...)
创建的任何实例都会继承这个方法。
函数也是对象,它们也有 proto 属性,在 JavaScript 中,所有的函数都是 Function 构造函数的实例,这意味着每个函数的 proto 属性都指向 Function.prototype
原型链(Prototype Chain)
原型链是JavaScript中一种通过__proto__
(非标准但常用)或Object.getPrototypeOf()
(标准)连接对象的机制。当访问一个对象的属性时,如果对象自身没有这个属性,JavaScript会沿着原型链向上查找,直到找到该属性或到达链的尽头(null
)。
示例代码:
function Animal(name) {
this.name = name;
}
Animal.prototype.speak = function() {
console.log(this.name + ' makes a sound.');
};
function Dog(name) {
Animal.call(this, name); // 借用Animal的构造函数
}
Dog.prototype = Object.create(Animal.prototype); // 原型链继承
Dog.prototype.constructor = Dog; // 修复constructor指向
Dog.prototype.bark = function() {
console.log(this.name + ' barks.');
};
const dog = new Dog('Rex');
dog.speak(); // Rex makes a sound.
dog.bark(); // Rex barks.
console.log(dog instanceof Dog); // true
console.log(dog instanceof Animal); // true
在这个例子中,Dog
通过Object.create(Animal.prototype)
继承了Animal
的原型,这意味着Dog
的实例(如dog
)在找不到某个属性或方法时,会沿着原型链向上到Animal.prototype
中查找。instanceof
操作符可以用来检测对象是否在其原型链中存在某个构造函数的原型。
总结
原型和原型链是JavaScript中非常重要的概念,它们允许对象继承其他对象的属性和方法。通过原型链,JavaScript实现了一种灵活的继承机制,使得代码更加模块化和可重用。希望这些代码示例能帮助您更好地理解这两个概念。