理解原型和原型链
JavaScript是弱类型,除了基本类型都可以理解为对象,这也是为什么说JavaScript中一切皆对象的原因。
不过在对象中函数比较特殊,对象就是由函数创造出来的,这听起来是不是有点先有鸡后有蛋,先有蛋后有鸡的感觉,这也跟后面要说到的原型有关。
先说prototype
属性,这个属性是函数
所独有的,函数也是对象也可以在自身定义属性和方法,那这个prototype
属性有什么用呢?
var a = {};
a.toString();
这里我并没有为a定义toString的方法,为什么可以调用呢?就跟prototype属性有关。
上面只是简写,如果通过构造函数是这样的
var a = new Object();
a.toString();
这里可以看到toString的方法,这也是为什么没有定义却没有报错的原因。
一个对象通过构造函数生成会执行下面四个步骤
- 创建一个新对象,作为要返回的实例
- 将新对象的原型(proto)指向构造函数的
prototype
属性 - 将内部的this指向新对象
- 执行内部代码,如果没有执行返回对象,则返回
this
(新对象)
从上面可以看到,对象的原型会指向生成对象函数的prototype
属性,对象本身如果没有属性或者方法,会向原型链查找,如果没有找到会一直找到Object.prototype
属性上,如果还没有找到就会返回undefined
。
Object.prototype
属性上还有原型链么?答案是有,是Null
。
上面简短的说了一下,下面通过例子的形式来结合
示例
var a = {};
这里我定义了一个对象a,根据上面说的每个对象都有一个原型,执行构造函数的prototype
下面就是原型图。
上面就是一个简单的原型图,下面说一下constructor
属性,这个属性有什么作用呢?
constructor
是prototype
对象下的一个属性,他指向一个函数,与函数的相互依存,还是通过上面变量a来说明吧。
可以看到,通过constructor
可以访问到构造函数,这个属性通常没有什么用,不过可以通用这个属性调用一些构造函数所独有的方法,比如Date
函数的now
方法
var a = new Date();
a.__proto__.constructor.now();
这里为了方便演示使用了_proto_
,不过在实际中不要这样写,因为这个属性只有浏览器才部署。
说了这么多,最后根据一张图,来总结一下。
首先对象是由构造函数创建的(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
自身,他是唯一一个通过自身生成函数的例子,这里只需要了解一下。
最后
说了这么多,原型链好像还没有被提起,每个对象都有自己的原型,原型的对象也是对象,一方面对象可以作为另一个对象的原型,这样层层链接起来的原型就成为原型链。