详解JavaScript原型与原型链

作者:代码拾荒时间:2026-10-24 06:13:57浏览:516

本文深入解析JavaScript中的原型与原型链机制。首先对比工厂方法与构造器方法两种对象创建方式,详细剖析new关键字的执行步骤及this指向。随后阐述原型的定义、constructor属性关联以及__proto__与[[Prototype]]的关系,最后通过属性查找规则完整揭示原型链在继承中的作用。

JavaScript对象创建基础

正如某些面向对象语言所具备的功能,在JavaScript中我们有时需要创建一个包含公共函数与属性的父类,以此减少代码重复、实现类型检查并构建更清晰的代码结构。在JavaScript中,继承机制是通过原型链来实现的。在深入理解JavaScript的继承与原型链之前,首先需要掌握JavaScript中对象的创建方式。

在JavaScript中创建对象

JavaScript中对象的创建方式主要有两种:工厂方法(Factory Functions)和构造器方法(Constructor Functions)。

工厂方法

工厂方法在编程领域是一种非类或非构造器的返回对象的方法。在JavaScript中,任何返回不使用new关键词创建对象的方法都被称为工厂方法。

工厂方法与构造器方法对比


function person(firstName, lastName, age) {
 const person = {};
 person.firstName = firstName;
 person.lastName = lastName;
 person.age = age;
 return person;
}

构造器方法

构造器方法与工厂方法的区别主要在于用例和命名规范。在命名规范上,构造器方法的名称首字母需要大写,且必须通过new关键词来调用构造器方法以生成实例。生成后的实例可以通过instanceof关键词进行检查。


function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
}

new的行为

当在工厂方法和构造器方法上同时使用new关键词创建对象时,工厂方法创建出的对象的__proto__属性指向Object.prototype,而构造器方法创建出的对象的__proto__属性则指向其自身的Xxx.prototype。

new关键字的执行机制


const mike = new person('mike', 'grand', 23);

mike.__proto__	// Object.prototype

const jack = new Person('jack', 'grand', 23);

jack.__proto__	// Person.protytype这里的prototype指向Person的Prototype Object
jack.__proto__.__proto__	// Object.prototype

new关键词在后台为构造器方法执行了以下几步

  1. 在构造器方法内部创建一个新对象,并将其赋值给this。
  2. 设置对象的[[Prototype]]和__proto__为原型的构造函数,这一步使得新对象的构造函数在构造新对象时被添加到原型链上。
  3. 如果该方法内部没有返回object、function或array类型的结果,则返回this。
  4. 如果该方法内部没有返回任何值,则返回this。

下面是一个展示new关键词在JavaScript引擎中执行效果的伪代码,注释部分用于示范new关键词添加语句的伪代码。


function Person(firstName, lastName, age) {
 // this = {};
 // this.__proto__ = Person.prototype;
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 // return this;
}

由于构造器方法上没有显式返回值,后台创建的this将被返回;而工厂方法内部由于返回了对象,因此后台不再添加return this,导致自然返回的内容不一致。

如果没有在构造器方法前使用new关键词,而是直接调用执行构造器方法,其仅作为一个普通方法来执行,而非作为构造器。


const bob = Person('bob', 'grand', 23);
bob	// undefined. 因为这里Person当作方法直接调用了且没有返回值
window.firstName	// bob. 函数内的this将指向全局作用域,导致意外操作

继承与原型链

原型

原型(Prototype)可以视为JavaScript方法的一个属性。每次在JavaScript代码中创建方法时,JavaScript引擎会自动添加一个名为prototype的属性。这个prototype属性是一个对象(即原型对象),该对象默认包含一个constructor属性,指向原方法对象。任何添加到prototype的属性和方法都位于这个对象中,该类的所有实例共享这个原型对象。实例对象的__proto__属性指向这个对象,方法的prototype属性也指向这个对象。

在ECMAScript标准中,object.[[Prototype]]是访问原型的方法,但在ECMAScript 2015中,建议使用Object.getPrototypeOf()和Object.setPrototypeOf()来替代。等价的__proto__是多数浏览器使用的事实上的、但非标准的实现。

原型的定义与访问


function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
}

Person.prototype === Person.prototype.constructor.prototype	// 指向Person的原型对象
Person.prototype.constructor === Person	// 指向Person方法对象

let bob = new Person("Bob", "Ross", 21);
Person.prototype === bob.__proto__;	// true

let alex = new Person("Alex", "Wang", 21);
Person.prototype === alex.__proto__;	// true
alex.__proto__ === bob.__proto__;	// true

原型链

首先我们需要了解对象的查找机制。当我们访问一个对象的属性时,JavaScript引擎会首先查找该对象本身是否包含对应属性;如果没有,则去对象的原型中查找;如果仍未找到,则继续去对象的原型对象的原型对象中查找,直至查询到对象的__proto__为null时停止。

JavaScript对象创建基础

原型链的查找规则


const obj = {};
console.log(obj);	// [object Object]	obj的toString()方法从Object的原型中查找到并使用

function Person(firstName, lastName, age) {
 this.firstName = firstName;
 this.lastName = lastName;
 this.age = age;
 // 在Person.prototype上定义了toString覆写了Object.prototype上的toString
 Person.prototype.toString = function() {
  return `${this.firstName} It Is`;
 }
}

let bob = new Person("Bob", "Ross", 21);
let alex = new Person("Alex", "Wang", 21);
console.log(bob);	// Bob It Is
console.log(alex);	// Alex It Is

以上就是详解JavaScript原型与原型链的详细内容,更多关于JavaScript原型与原型链的资料请关注本站其它相关文章!

作者最新文章