yliu

时来天地皆同力,运去英雄不自由

理解原型和原型链


参考: 深入理解javascript原型和闭包(完结)

JavaScript是弱类型,除了基本类型都可以理解为对象,这也是为什么说JavaScript中一切皆对象的原因。

不过在对象中函数比较特殊,对象就是由函数创造出来的,这听起来是不是有点先有鸡后有蛋,先有蛋后有鸡的感觉,这也跟后面要说到的原型有关。

先说prototype属性,这个属性是函数所独有的,函数也是对象也可以在自身定义属性和方法,那这个prototype属性有什么用呢?

var a = {};
a.toString();

这里我并没有为a定义toString的方法,为什么可以调用呢?就跟prototype属性有关。

上面只是简写,如果通过构造函数是这样的

var a = new Object();
a.toString();

https://pic1.zhimg.com/80/v2-038c5818398efc6b4e990b3c2fb3b54c_hd.jpg 这里可以看到toString的方法,这也是为什么没有定义却没有报错的原因。

一个对象通过构造函数生成会执行下面四个步骤

  1. 创建一个新对象,作为要返回的实例
  2. 将新对象的原型(proto)指向构造函数的prototype属性
  3. 将内部的this指向新对象
  4. 执行内部代码,如果没有执行返回对象,则返回this(新对象)

从上面可以看到,对象的原型会指向生成对象函数的prototype属性,对象本身如果没有属性或者方法,会向原型链查找,如果没有找到会一直找到Object.prototype属性上,如果还没有找到就会返回undefinedObject.prototype属性上还有原型链么?答案是有,是Null

上面简短的说了一下,下面通过例子的形式来结合

示例

var a = {};

这里我定义了一个对象a,根据上面说的每个对象都有一个原型,执行构造函数的prototype下面就是原型图。 https://pic4.zhimg.com/80/v2-c93843e5905a3990c0b1147d0dad7f03_hd.jpg 上面就是一个简单的原型图,下面说一下constructor属性,这个属性有什么作用呢? constructorprototype对象下的一个属性,他指向一个函数,与函数的相互依存,还是通过上面变量a来说明吧。 https://pic1.zhimg.com/80/v2-94e4180728a52844d1204a830249c10c_hd.jpg

可以看到,通过constructor可以访问到构造函数,这个属性通常没有什么用,不过可以通用这个属性调用一些构造函数所独有的方法,比如Date函数的now方法

var a = new Date();
a.__proto__.constructor.now();

这里为了方便演示使用了_proto_,不过在实际中不要这样写,因为这个属性只有浏览器才部署。 https://pic3.zhimg.com/80/v2-3ee04ff512a68800c014b66de0f6b3f2_hd.jpg 说了这么多,最后根据一张图,来总结一下。

首先对象是由构造函数创建的(Object),你可能有疑问,函数也是对象,那么函数的__proto__指向什么? 答案是Function.prototype,所有函数都是由Fcuntion创建的,举个例子

var a = new Function('a', 'b', 'return a + b');
a(1, 2);

这里a的__proto__等于Function.prototype,之前说过prototype是一个对象,所以Function.prototype指向Object.prototype。 最后说一点,Function.__proto__指向的是Function自身,他是唯一一个通过自身生成函数的例子,这里只需要了解一下。

最后

说了这么多,原型链好像还没有被提起,每个对象都有自己的原型,原型的对象也是对象,一方面对象可以作为另一个对象的原型,这样层层链接起来的原型就成为原型链。