该节思路及部分代码插图摘自 王福朋的博客 第4,5小节(尊重原创也方便自己查阅O(∩_∩)O哈哈~)
本打算一天讨论完的问题,刚好有个周末无心学习,再加上真正写出来的时候远没有自己理解的时候想的那么简单,最后横跨4天,罪过/(ㄒoㄒ)/~~
闲话不多说了,按原计划这节说说__proto__以及与prototype更深层的关系,下节计划看看继承有什么以前没注意到的问题。OK,go!
__proto__是什么
在第一节的讨论学习中我们知道了,每个函数都有一个prototype,每个对象都有__proto__,每个对象的__proto__指向创建他的函数的prototype,这几句总结对于记忆和理解很有帮助。举个栗子:
可以看出来,obj的__proto__和Object的prototype是全等的!这是因为obj={}相当于obj=new Object();,obj实质是由Object实例化的对象,也佐证了上文我们得到的观点。
但还是有个特例,Object.prototype.__proto__是指向null的,这点需要记住。
还有一个问题,第一节我们根据定义得到了,函数也是对象,那么函数有自己的__proto__属性吗?当然有!我们一起分析一下
1 function fn(x,y){ 2 return(x+y); 3 } 4 console.log(fn(1,2)) //3 5 6 7 var newFn = new Function('x','y','return(x+y);'); 8 console.log(newFn(1,2)) //3
第二种函数创建的方法使用Function构造函数创建的,只是为了说明一个问题,函数作为对象也是由函数创建的,那么根据上文的总结分析,对象的__proto__指向创建他的那个函数的prototype,我们不难得出:Object.__proto__===Function.prototype,甚至是这样Function.__proto__===Function.prototype。到这是不是可以根据我们那句总结很好的理解这个__proto__了,那么问题又来了,我们也知道函数的prototype属性也是个对象,那么这个对象是不是由所有对象的超类Object创建的呢,答案是肯定的,所以有:Function.prototype.__proto__===Object.prototype.
对象原型组成的链条-原型链
在我们实际的开发和学习过程中,免不了用到这个操作符:instanceof,具体用法回顾一下:
1 function Fn(){}; 2 3 var fn1=new Fn(); 4 fn1 instanceof Fn; //true 5 fn1 instanceof Object; //true
fn1是Fn的实例化对象,那结果为true我们不意外,那为什么Object的测试结果也为true呢,好,我们先分析一下这个操作符:
(图片来源http://www.ibm.com/developerworks/cn/web/1306_jiangjj_jsinstanceof/figure1.jpg)
我们可以看到两条常规线条,一条是对象原型__proto__(命名为A线),一条是函数原型属性prototype(B线),那么
沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false。这样我们就不难得出fn1 instanceof Object为true,而且通过这种不断上溯的方式我们也能推出这几个恒等式:
1 Function instanceof Function; 2 Object instanceof Function; 3 Function instanceof Object; 4 Object instanceof Object;
总结一下:
Function作为一个函数是由他本身Function创建的,Function作为一个对象是由Object创建的,Object作为一个函数由Function创建,Object作为一个对象也由他本身Object创建。现在函数和对象的关系理清了吧,函数也是对象,这句话很重要。
所以说instanceof讲的就是一种原型链的关系,通过这种看不见的链条来判断继承关系,下节我们一起来关注一下继承和原型链的暧昧关系。