以下是总结一下,网上太多画图的,说明的,弯弯绕绕,云里雾里,很难让人简单理解,这里对一些常见的名词【换个说法】,可能好理解一点
理解下面几点,对于理解js的原型链,__proto__
,prototype,constructor有帮助:
- js里,函数是对象,函数可以赋值给变量,也可以当参数传递,还可以通过new 函数,创建对象
- 区分【定义对象】与【实例对象】,【定义对象的字面量】
- 【定义对象】是
function Person{}
这样的定义,Person就是定义对象,只是定义,只有new或者函数调用了才能用,是【new实例对象时候的模板】(new出来的对象的属性,就是这个定义对象里面定义的) - 【实例对象】是
var person1 = new Person()
这样,person1就是实例对象,可以在js里面调用了 - 【定义对象的字面量】,就是定义函数的【文字】表示
-
js【实例对象】属性查找过程 (【原型链及作用】),如果在实例对象上没有,就会顺着原型
__proto__
向上找,直到__proto__
为null -
原型
__proto__
,就是指向创建对象的定义对象,构造函数。new出来的实例对象,原型就是定义对象;直接{}
出来的对象,默认原型为Object,Object的原型为null
上图看出,aa是new出来,所以原型是Person构造函数,bb是空对象,原型为Object
下面是原型链,属性调用查找
-
prototype
是【定义对象】的【“this”指针】(类似new以后,实例对象使用的指针,这里的这个this,指所【定义对象本身】,也可以理解为指向【定义对象的字面量】),可以对【定义对象】添加属性与方法,【只有函数】才有可以这样理解: 当定义对象在回车或js运行后,此时的定义对象【成为】js的普通函数(里面有个专门属性prototype【保存】了【原始】的函数字面量),可以直接函数调用 当使用【new 操作符】之后,js会通过【原始函数字面量】生成一个对象 所以才有 函数.prototype.constructor == 实例.constructor , 说明 函数与实例是从【同一个】函数字面量生成
function Person() {
}
Person.prototype.name = '张三';
__proto__
是【实例对象】的【属性】,【指向】【定义对象】的“this”指针(Person.prototype),【所有】对象都有,原型链,原型就是说这个属性
var person = new Person();
console.log(person.__proto__ === Person.prototype);
constructor
就是【构造】这个对象时使用的对象,定义对象是通过Function创建,实例对象通过定义对象的【字面量】创建。所以实例对象与定义对象都有constructor
,但是【不相等】,而定义对象的prototype (类似“this指针”)指向定义对象的字面量,所以定义对象.prototype.constructor == 实例对象.constructor
【主要用在】闭包内,把对象赋值给变量,变量.constructor.prototype
这样的形式,扩展定义对象,因为闭包内的函数,外界不能访问
constructor常见用法,扩展闭包内的对象属性
- Object,理解为,js内部定义了的一个
function Object{}
,所有对象的原型链顶端是Object
小练习
从上面看出,使用prototype增加的属性,可以直接被【已经实例化】的对象直接调用,就是通过prototype修改了【定义对象】,也可以看出对象属性查找过程,需要aa.ddd
但是实例对象aa没有,通过原型找到Person,再找属性
js中其他普通变量的原型链,就是在js中,声明的变量,字符串,数字,true,原型分别为String,Number,Boolean,而这些原型的都是来自Object