(三)、JavaScript原型链
原型链
在 JavaScript 中,对象之间的继承是通过原型链来实现的。每个对象都有一个指向原型对象的内部链接,也就是 [[Prototype]] 属性。这个链接的作用是如果对象本身没有某个属性或方法,就会去它的原型对象上找,如果还没有,就会去原型对象的原型对象上找,以此类推,直到找到为止。这就形成了原型链。
原型链的实现
在 JavaScript 中,我们可以通过构造函数来创建一个对象,每个构造函数都有一个 prototype 属性,它指向一个对象,这个对象就是新对象的原型对象。通过 new 关键字调用构造函数时,会创建一个新的对象,并将它的原型对象指向构造函数的 prototype 属性所指向的对象。
下面是一个例子:
// 定义一个构造函数
function Person(name) {
this.name = name;
}
// 定义构造函数的原型对象
Person.prototype.sayHello = function() {
console.log(`Hello, my name is ${this.name}`);
};
// 创建一个对象
const person = new Person('John');
// 调用对象的方法
person.sayHello(); // 输出 "Hello, my name is John"
在这个例子中,Person 构造函数有一个 prototype 属性,指向一个对象,这个对象有一个 sayHello 方法。当我们通过 new 关键字调用 Person 构造函数时,会创建一个新对象 person,并将它的原型对象指向 Person.prototype 所指向的对象。
因此,当我们调用 person.sayHello() 方法时,JavaScript 引擎会首先查找 person 对象本身是否有 sayHello 方法,如果没有,就会去它的原型对象 Person.prototype 上查找,如果还没有,就会去 Person.prototype 的原型对象 Object.prototype 上查找,以此类推,直到找到为止。
原型链的示意图
下面是一个原型链的示意图:
+-------------+
| Object |
+-------------+
^
|
+-------------+
| Prototype |
+-------------+
^
|
+-------------+
| Prototype |
+-------------+
^
|
+-------------+
| Prototype |
+-------------+
^
|
+-------------+
| Person |
+-------------+
^
|
+-------------+
| Prototype |
+-------------+
^
|
+-------------+
| Prototype |
+-------------+
^
|
+-------+
| john |
+-------+
以上代码示例展示了一个简单的原型链,其中:
-
Object是所有对象的基类,也是原型链的起点;
-
每个对象都有一个Prototype属性,指向它的原型对象;
-
原型对象也有一个Prototype属性,指向它的原型对象;
-
原型对象最终指向Object.prototype;
-
通过原型链的方式,子类可以访问父类原型上的属性和方法;
-
在上述示例中,john对象通过原型链可以访问到Person.prototype和Object.prototype上的属性和方法。
接下来我们来看一个实际的例子,更好地理解原型链的实现。
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
console.log("Hello, my name is " + this.name);
};
function Student(name, major) {
this.name = name;
this.major = major;
}
// 设置 Student 的原型对象为 Person 的实例
Student.prototype = new Person();
Student.prototype.sayMajor = function() {
console.log("My major is " + this.major);
};
var student1 = new Student("Alice", "Mathematics");
student1.sayHello(); // "Hello, my name is Alice"
student1.sayMajor(); // "My major is Mathematics"
在这个例子中,我们定义了 Person 和 Student 两个构造函数,并且让 Student 的原型对象指向 Person 的一个实例。这个实例就构成了一个原型链,它包含了 Student.prototype、Person.prototype 和 Object.prototype 三个节点,构成了一个链式结构。
当我们调用 student1.sayHello() 方法时,JavaScript 引擎首先在 student1 实例中查找 sayHello() 方法,发现没有找到,于是它继续在 Student.prototype 中查找,仍然没有找到,接着在 Person.prototype 中查找,这次找到了 sayHello() 方法并调用。当调用完 sayHello() 方法后,程序继续执行 student1.sayMajor() 方法,这次 JavaScript 引擎会在 student1 实例中查找 sayMajor() 方法,没有找到,接着在 Student.prototype 中查找,找到了 sayMajor() 方法并调用。
这个例子展示了原型链的实际应用,通过原型链,我们可以在子类中访问父类的属性和方法,并且可以在子类中扩展新的属性和方法。原型链也是 JavaScript 中继承的基础实现机制之一。
最后再给出一个简单的总结:原型链是由原型对象构成的链式结构,JavaScript 引擎在查找属性或方法时会沿着原型链逐级查找,直到找到或者查找到顶层为止。
共享资源关注公众号获取
本文由 mdnice 多平台发布