JS的原型链

"JS是如何刨根问底的"

Posted by Mzx on May 23, 2017

JS的原型链

本文阐述了js中的prototype,constructor和__proto__之间的关系。 同时梳理了js如何实现继承的。

属性释义

  • prototype
    prototypeJS中除了通过bind()生成的函数外所有function都具有的属性,其值为一个对象,对象里包含两个 值(__proto__和constructor)。作用是存储要共享的属性和方法。
  • __proto__([[Prototype]])
    __proto__是JS中每个对象都有的属性,其值指向了该对象构造函数的prototype
  • constructor
    constructor即构造函数,构造函数就是构造函数,其值为函数本身。

实例属性与类属性

  • 类属性是指绑定到prototype上的属性,可以被所有通过该构造函数创建的实例继承。
  • 实例属性是指绑定到this上的属性,可通过在构造函数内给对象init时绑定或者直接在 生成对象后绑定。其值是不可共享的。

属性之间的关系


图片来自 mollypages.org

//定义一个构造函数 
var Foo = function(){}

此时[1] Foo.prototype = {constructor: Foo, __proto__:Object.prototype}
即:Foo.prototype.__proto__ === Object.prototype,
因为 Foo.prototype的值是个Object实例,
所以[3] {}.__proto__ = Object.prototype

console.log(Foo.prototype.__proto__ === Object.prototype
console.log(Foo.prototype.constructor === Foo)
var f1 = new Foo()
//此时[2] f1.__proto__ === Foo.prototype
console.log(f1.__proto__ === Foo.prototype)

Foo是我们自定义的构造函数,JS内置的构造函数也是同样的如Object,这里的Object是个构造函数
Object.prototype = {constructor: Object, __proto__: null}

console.log(Object.prototype.__proto__)
//null

为什么[4] Object.prototype.__proto__会是null呢? Object.prototype 不是为 {} 吗, {}.__proto__不应该 是Object.prototype吗?而且我们自定义的构造函数就是这个样子呀!

如果设置Object.prototype.__proto__ = Object.prototype 那么,当查找一个不存在的属性时,JS 会从上级原型链去查这个属性,便会出现死循环,所以ES5规定Object.prototype.__proto__ = null 而且Object.prototype 指向的对象并不是继承自Object,即它不是Object的实例。

原文:15.2.4

The value of the [[Prototype]] internal property of the Object prototype object is null, the value of the [[Class]] internal property is “Object”, and the initial value of the [[Extensible]] internal property is true.

上面提到JS内置的构造函数Object,在JS中函数也是一种对象,即也存在Object.__proto__ 那么它指向谁呢?当然是Function.prototype了,因为 Functionjs中所有function的构造函数,所以function Object(){}Function的一个实例。 所以[7] Object.__proto__ === Function.prototype

console.log(Object.__proto__ === Function.prototype)
//true

JSFunction也是一个构造函数。 所以[9] Function.prototype = {constructor: Function, __proto__: Object.prototype}, [10] Function.__proto__ = Function.prototype

至此便是一个完整的JS原型链。