外观
JavaScript-原型链解析
1346字约4分钟
2025-01-05
JavaScript-原型链解析
本篇通过 图解 和 示例 重新梳理一下 JavaScript 中的原型链。
原型
每个对象都有一个与之关联的另一个对象,这个对象称为原型,并且该对象的所有属性和方法都被关联对象的实例所共享。
原型链
当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是
Object.prototype,最后就是null。
prototype
每个函数都有一个 prototype 属性,这个属性是一个对象,这个对象包含了通过构造函数创建的所有实例共享的属性和方法。也就是说,当我们创建一个函数时,JavaScript 会自动为这个函数创建一个 prototype 对象,并且这个对象有一个 constructor 属性,指向这个函数。
- 特别注意:只有函数对象才有 prototype 属性,普通对象是没有的。
function Person() {}
console.log(Person.prototype) // object {constructor: ƒ Person(), <prototype>: Object}
const person = new Person()
console.log(person.prototype) // undefined
Person.prototype 是一个对象,它通常包含以下两个属性:
constructor:constructor属性指向创建该原型对象的构造函数。在上面例子中,Person.prototype.constructor将指向Person。
function Person() {}
console.log(Person.prototype.constructor === Person) // true<prototype>:<prototype>是一个表示原型链的概念,通常用__proto__来表示。每个对象都有一个__proto__属性,它指向该对象的原型对象。对于Person.prototype来说,它的__proto__属性指向Object.prototype,因为所有对象最终都继承自Object。
function Person() {}
console.log(Person.prototype.__proto__ === Object.prototype) // true用图表示如下: 
__proto__
每个对象都有一个
__proto__属性,这个属性指向该对象的原型。当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的__proto__属性指向的对象里找这个属性,这个__proto__属性又会有自己的__proto__属性,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是Object.prototype,最后就是null。
function Person() {}
const person = new Person()
console.log(Person.__proto__) // function () { [native code] }
console.log(person.__proto__) // object {constructor: ƒ Person(), <prototype>: Object}
如上,Person.__proto__ 是一个函数对象,它指向 Function.prototype,因为所有函数最终都继承自 Function。 也就是说,Perosn 是由 Function 构造函数创建的一个实例。
console.log(Person.__proto__ === Function.prototype) // trueperson.__proto__ 是一个对象,它指向 Person.prototype,因为 person 是通过 Person 构造函数创建的。
console.log(person.__proto__ === Person.prototype) // true更新图表示如下: 
constructor
每个原型对象都有一个 constructor 属性,这个属性指向该原型对象对应的构造函数。也就是说,当我们创建一个函数时,JavaScript 会自动为这个函数创建一个 prototype 对象,并且这个对象有一个 constructor 属性,指向这个函数。
console.log(Person.prototype.constructor === Person) // true再上面图表中,只列出了 Function.prototype 和 Object.prototype。我们添加上 Function 和 Object 构造函数和 Function.prototype 和 Object.prototype 的关系。
同时更新一下原型链的尽头 null。即 Object.prototype.__proto__ 指向 null。
更新图表如下:

Function
Function 是 JavaScript 中所有函数的构造函数。
也就是说,所有的函数都是通过 Function 构造函数创建的实例。同时,Function 本身也是一个函数,它也是通过 Function 构造函数创建的实例。
因此,Function.prototype 与 Function.__proto__ 指向同一个对象。 Function.prototype 和 Function.__proto__ 是相等的。
我们通过代码来验证一下:
console.log(Function.prototype)
console.log(Function.__proto__)
console.log(Function.__proto__ == Function.prototype) // true
console.log(Function.prototype.__proto__ === Object.prototype) // true
我们更新一下图表:

Function.prototype 也有一个 __proto__ 属性,它指向 Object.prototype,因为所有对象最终都继承自 Object。
console.log(Function.prototype.__proto__ === Object.prototype) // true更新图表如下: 
Object
所有对象的最顶层原型都是 Object.prototype 包括普通对象和函数对象。
而 Object.prototype 的原型是 null。
console.log(Object.prototype.__proto__ === null) // true
function Person() {}
const person = new Person()
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(person.__proto__.__proto__ === Object.prototype) // true而 Object 本身也是一个函数,它也是通过 Function 构造函数创建的实例。因此,Object.__proto__ 指向 Function.prototype。
console.log(Object.__proto__)
console.log(Object.__proto__ === Function.prototype) // true
我们更新一下图表:

总结
总的来说,涉及原型链一共有三个重要点:prototype、__proto__ 和 constructor。
prototype:每个函数都有一个prototype属性,这个属性指向该函数的原型对象。原型对象是一个普通的对象,它有一个constructor属性,指向该函数。__proto__:每个对象都有一个__proto__属性(函数对象也有该属性)这个属性指向该对象的原型。原型对象也有一个__proto__属性,指向它的原型。这样一层一层地往上找,就形成了一个原型链。constructor:每个原型对象都有一个constructor属性,这个属性指向该原型对象对应的构造函数。
我们可以通过不断来的打印和对比函数和对象的prototype、__proto__,来找出原型链的规律。
