js原型、原型链详解

179 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。详情

原型及原型链

这是本人珍藏的图,关系一目了然。

原型链&构造函数.png

概念

  • 显示原型prototype函数/方法拥有一个prototype属性,指向函数的原型对象。

    (通过Function.prototype.bind方法构建的函数没有prototype属性)

  • 隐式原型__proto__任意对象都有一个内置属性[[prototype]],大多浏览器支持通过__proto__来访问,在ES5中有了对这个内置属性的标准Get方法:Object.getPrototypeOf()

    (Object.prototype 这个对象是个例外,它的__proto__值为null ) (到终点)

  • 原型链:这些对象及原型对象通过__proto__属性链接形成的链路结构就行原型链。原型链是由多级父对象逐级继承形成的。原型链保存着一个对象可用的所有属性和方法。原型链控制着属性和方法的使用顺序:就近原则--先子级后父级

  • 关系:instance.constructor.prototype = instance.__proto__

    实例的构造函数的原型对象prototype就是实例对象的原型proto

    1. 实例通过new 构造函数()得到
    2. 实例的constructor是构造函数
    3. 实例的原型__proto__就是构造函数的原型对象prototype
    4. 构造函数constructorprototype是一对相互反指的

    看一下下面的例子帮助理解:

    function Person(name) { // 构造函数
        this.name = name
    }
    var lisa = new Person('lisa')   // 生成实例对象
    // 1.函数的prototype原型对象的构造函数是自身
    Person.prototype.constructor === Person // true// 2.实例与构造函数之间的关系
    lisa.constructor === Person // true
    lisa.__proto__ === Person.prototype // true
    lisa.__proto__ === lisa.constructor.prototype   // true// 3.构造函数与内置类型Function的关系(function定义的时候相当于new Function()操作)
    Person.constructor === Function  // true
    Person.__proto__ === Function.prototype  // true
    Person.__proto__ === Person.constructor.prototype   // true// 直接定义对象与内置类型Object的关系
    var obj = {}    // 直接定义对象相当于new Object()操作
    obj.constructor === Object  // true
    obj.__proto__ === Object.prototype  // true

内置类型FunctionObjectArrayDate等都是函数,且可以做构造函数,它们之间的关系: 所有对象Object这个构造函数的原型对象prototype最终都指向Object.prototypeObject.prototype这个对象的原型指向null(终点)。

// 1. 特殊函数Function
Function.constructor === Function
Function.prototype === Function.__proto__
Function.prototype.__proto__ === Object.prototype
// 可以理解为:Function既是构造函数又是自己的实例
// 所以Function作为构造函数时的原型对象(prototype)就是Function作为实例时的原型__proto__
// Function.prototype原型对象也是对象,所以这个对象的原型就是Object.prototype

// 2. 特殊对象Object.prototype与构造函数Object
Object.constructor === Function
Object.prototype.constructor === Object
// Object.prototype原型对象也是对象
// Object.prototype作为对象时的构造函数就是Object
Object.prototype === Object.prototype
// 上式可以理解为:构造函数Object的原型对象prototype 就是 Object.prototype这个对象

// 3. 其他内置类型(函数)的构造函数都是Function
Array.constructor === Function
Date.constructor === Function
Array.__proto__ === Function.prototype
Date.__proto__ === Function.prototype
Array.prototype.__proto__ === Object.prototype
Date.prototype.__proto__ === Object.prototype
// Array/Dat是函数,可以看作new Function()得到的实例
// 它们的构造函数都是Function
// 它们作为实例时的原型__proto__就是其构造函数的原型对象Function.prototype
// 它们作为构造函数时的原型对象Array.prototype这个对象的原型__proto__就是Object.prototype

// 4. 内置类型创建的实例(以数组为例)
[].constructor === Array    // 直接定义数组[]相当于new Array()操作
[]__proto__ === Array.prototype // 实例的原型__proto__是其构造函数的prototype
[].__proto__.__proto__ === Object.prototype

结合以上,我们来看原型链:

function Person() {}
var lili = new Person()
lili.__proto__ === Person.prototype // 实例原型是构造函数的原型对象
Person.prototype.__proto__ === Object.prototype
// Person没有自定的父类了,Person.prototype是对象,所以其父类就是Object
lili.__proto__.proto__ === Object.prototype
lili.__proto__.proto__.__proto__ === null
// 这个一直向上查找原型__proto__直到null的链路就是原型链

总结

  1. 任何对象都有其原型__proto__属性,函数有作为对象的__proto__属性也有作为函数的prototype属性。
  2. (构造函数创建出来的)实例对象的原型__proto__是其构造函数的原型对象prototype
  3. 函数的原型对象的构造函数是其自身fun.prototype.constructor===fun
  4. Object.prototype这个对象的原型是null(原型链的终点)