JavaScript中的prototype及原型链
我们可以将JavaScript中的对象分为两大类:普通对象和函数对象。两者之间的关系是:普通对象是由函数对象new出来的。如var t = new T()
中的T
(函数对象)和t
(普通对象),普通对象t
是由函数对象T
new出来的。
prototype
prototype只有函数对象才有的属性。使用prototype可以保证new出来的所有普通对象都使用的是同一个方法,也减少了内存的占用。
如Array
的prototype包含了以下方法:
Array.prototype
//constructor:f
//concat:f
//push:f
//pop:f
//shift:f
//...
因此,如果想同时让所有普通对象公用某属性或方法,可以定义在函数对象的prototype上。不过,并不建议直接操作JavaScript内置函数对象的prototype
原型链
首先上一张mdn上关于prototype、__proto__、constructor之间关系的照片。如下所示:
下边用代码来“翻译”以下图片内容
function T(){}
console.log(T.prototype)
//{constructor: ƒ}constructor: ƒ T()__proto__: Object
T.prototype.constructor
//f T(){}
var t = new T()
t.__proto__
//{constructor: ƒ}constructor: ƒ T()__proto__: Object
t.__proto__ === T.prototype
//true
T.prototype.__proto__ === Object.prototype
//true
那么,现在有一个前提条件是:普通对象只有__proto__
,没有prototype
;函数对象则同时持有__proto__
和prototype
。如下证据
t.prototype//undefined
现在来总结一下已有的事实:
- 普通对象是由函数对象new出来的
- 普通对象只有
__proto__
,没有prototype
- 普通对象的
__proto__
指向new出这个普通对象的函数对象的prototype
- 函数对象拥有
prototype
属性 - 函数对象的
prototype
属性又有__proto__
属性 函数.prototype.__proto__
指向派生出这个函数的函数的prototype
- 综上,由
prototype
和__proto__
组成了一条所谓的原型链
,可以用来追溯 普通对象与函数对象、函数与函数 之间的派生关系。 - 因为
Object.prototype.__proto__
为null,所以说JavaScript中一切皆为对象
,因为追溯到Object.prototype.__proto__
就到头了。