深入浅出 - 原型到原型链

概念图


图片来自http://www.mollypages.org/tutorials/js.mp

对象的继承

实质,对象的继承,继承是的原型对象的 prototype。当对象在自身找不到对应的属性时,便会通过原型链向上查找,直到找到对应的属性或者查找到 Object.prototype 还未找到便终止查找。

对象的继承,不是普通的复制操作,而是创建关联性。因为这种关联性,所以避免修改基础类型的prototype

访问原型

  • __proto__ 是非标准的方法,但被绝大部分浏览器所支持。
  • Object.getPrototypeOf 则为标准的访问原型的方法。
  • Object.getPrototypeOf(obj) === obj.__proto__ 是等价的。

构造函数

常见的几大基础构造器:

  • Object
  • Function
  • Number
  • Boolean
  • String

案例一:

function Foo() {}
var foo = new Foo() // 对象

// 实例对象不存在prototype也无法通过new关键字构建实例
console.log(foo.prototype) // undefined
new foo() // Uncaught TypeError: foo is not a constructor

// 而函数十分特殊
var func = new Function()
console.log(func.prototype) // {constructor: ƒ}
console.log(new func()) // {}

除了函数,所有实例对象不存在prototype,也无法通过new关键字构建实例。

案例二:

function Foo() {}
Foo.__proto__ === Function.prototype // true
String.__proto__ ===Function.prototype // true
Object.__proto__ === Function.prototype // true
Number.__proto__ === Function.prototype // true
Boolean.__proto__ ===Function.prototype // true

Function.prototype为所有构造函数的原型(包含基础类型Object,Number,String…)

案例三:

Function.__proto__ === Object.prototype // true
Object.prototype.__proto__ === null // true

Object.prototype是最底层的对象原型

补充

  • 验证原型对象与实例对象之间的关系: instanceof
  • 原型与构造函数,是否从属关系:constructor
  • 原型对象和某个实例之间的关系: 构造函数.prototype.isPrototypeOf(‘实例’)
  • 检查原型是否存在某个属性:’assign’ in Object
  • 在改变对象的prototype时,会直接改变改该对象的constructor,为了避免该对象实例的继承链紊乱,所以后续需要手动将它的constructor绑定回原构建函数

总结

  • 所有实例对象(不主动赋值prototype)本身不存在prototype,但是函数(箭头函数除外)是特殊的,它具有 prototype,能再次new来建构属于自身的实例。

  • Function.prototype为所有构造函数的原型(包含基础类型Object,Number,String…)

  • 整个浏览器最先存在的万物之根是 Object.prototype ,随后需要各类构造器构造更多的对象才有了继承 Object.prototypeFunction.prototype

为了让 Object 也能直接构造它的实例对象,所以它继承了 Function.prototype 。对此每个人的见解各不相同,由此引出了先有鸡还是先有蛋的问题。看完这篇, 希望你能找出属于你的答案。

参考文章

  1. JavaScript深入之从原型到原型链
  2. proto和prototype来深入理解JS对象和原型链
  3. 从探究Function.proto===Function.prototype过程中的一些收获
  4. Javascript面向对象编程(二):构造函数的继承