JavaScript中的原型(prototype)和原型链(prototype chain)是其面向对象编程的基础。这两个概念是理解JavaScript中对象之间的关系和继承机制非常关键的部分。
原型(Prototype)
在JavaScript中,每一个函数创建时都会有一个名为 prototype
的属性,这个属性是一个对象,它包含了可以由特定类型的所有实例共享的属性和方法。这意味着你可以使用原型来添加或者分享功能,而不需要在每个实例中重新定义这些功能。
例如,假设我们定义了一个构造函数:
javascriptfunction Person(name) { this.name = name; } Person.prototype.sayName = function() { console.log(this.name); };
以下是通过 Person
构造函数创建的两个实例:
javascriptvar person1 = new Person("Alice"); var person2 = new Person("Bob");
这里的 person1
和 person2
都没有自己的 sayName
方法。当你调用 person1.sayName()
时,JavaScript会查找 person1
是否有这个方法。由于 person1
没有,它会通过原型链查找 Person.prototype
是否有 sayName
方法。这样,person1
和 person2
实际上共享了 Person.prototype
上的 sayName
方法。
原型链(Prototype Chain)
原型链是JavaScript实现继承的机制。每个对象都有一个内部链接到另一个对象,即它的原型。这个原型对象本身也有一个原型,以此类推,直到某个对象的原型为 null
。按照规范,null
的原型没有原型,这通常被视为原型链的末端。
当你尝试访问一个对象的属性时,如果该对象本身没有这个属性,JavaScript引擎会沿着原型链向上查找,直到找到这个属性或者到达原型链的末端。
继续上面的例子,我们可以看到原型链是如何工作的:
javascriptperson1.sayName(); // 输出: Alice
- 首先,JavaScript引擎检查
person1
自身是否有sayName
属性。 - 发现
person1
没有,引擎接着检查person1
的原型(即Person.prototype
)。 Person.prototype
有sayName
方法,所以这个方法被调用。
如果我们有一个对象的原型是另一个对象,那么第二个对象的属性和方法也可以被第一个对象访问。这个过程可以一直持续下去,形成了一个“链”。
通过原型链实现继承
我们可以使用原型链来实现继承。例如,如果我们有一个 Employee
构造函数,它应该继承 Person
:
javascriptfunction Employee(name, title) { Person.call(this, name); // 继承属性 this.title = title; } Employee.prototype = Object.create(Person.prototype); Employee.prototype.constructor = Employee; Employee.prototype.sayTitle = function() { console.log(this.title); }; var employee1 = new Employee("Charlie", "Developer"); employee1.sayName(); // 输出: Charlie employee1.sayTitle(); // 输出: Developer
在这里,Employee.prototype
被设置为一个新对象,这个新对象的原型是 Person.prototype
。这样,Employee
的所有实例都继承了 Person
的方法。我们还修正了 Employee.prototype.constructor
属性,确保它指向正确的构造函数。
通过上面的代码,我们创建了一个 Employee
的实例 employee1
,它能够调用继承自 Person
的 sayName
方法,同时还有自己特有的 sayTitle
方法。