前端入门水平,根据个人体会总结下JavaScript中的prototype和__proto__属性,高手就略过吧。
本文根据一个实际例子来说明这两个属性的区别,先看一张图吧:
1. 先对上图进行描述下:
图中主要包括:原生Object类对象、Function类对象、以及我自定义的一个娄:Man( function Man(){ this.name="tuanfe"; this.age =25;})、
以及man对象(var man = new Man())、带有虚线的框是中间对象,为了好说明我就这样画出来了。
图上注明的什么类型,如function类型、object类型,这个我是通过typeof函数方法得到的。
如果大家也想跟着实践下,在chrome的控制台上,通过使用console.log()和console.dir()方法进行实践,console.dir()方法是表示输出对象的所有属性。
2. 总结这两个属性
上面的草图表述得非常明显:
(1)通过new出来的对象只有__proto__属性,而定义的function Man(){},Object,Function都具有prototype和__proto__属性;
(2)man.__proto__和Man.prototype都指向同一个对象,用console.log(typeof man.__proto__)的结果是object,因此指向的对象是object类型;
(3)Function的prototype和__proto__指向同一个function对象:function Empty(){},且它里面的__proto__是指向Object;
(4)Object的prototype指向的是一个object类型的Object对象,与Man中的prototype的类型是一样的;
(5)__proto__属性其实在原型链中起着非常重要的作用。如果我调用man.getName()方法,首先会在man这个对象的自身属性去查找这个方法,如果没有,根据__proto__所指向的对象去它里面查找是否有这个方法,如果没有根据Man这个中间对象的__proto__属性指针到Object对象中去查找,直接找到该定义的方法,如果没有就报错;这也体现出我们原型继承的思想。
(6)通过Man的prototype增加其他属性或方法,这相当于C++中的静态成员和静态方法,让实例化的对象能通过原型继承机制共享静态成员或静态方法。当我直接调用Man.test()方法时,如果在当前Man中没有找到,就通过__proto__属性到function Empty(){}中去寻找,如果没有找到,通过function Empty(){}中中的__proto__到Object里去找,也就是说原型链的继承机制最后到顶层就是到Object对象中进行查找,如果在这里还没有找到就要报错了。
(7)其实在上图中也还能发现其他很多规律,读者可以自行总结。