感觉这道题目是面向对象中比较经典了题目了.先上代码,然后分析
1 function Foo(){
2 getName = function(){console.log(1);};
3 return this;
4 }
5 Foo.getName = function(){console.log(2);};
6 Foo.prototype.getName = function(){console.log(3);};
7 var getName = function(){console.log(4);};
8 function getName(){console.log(5);}
9 Foo.getName();//2
10 getName();//4
11 Foo().getName();//1
12 getName();//1
13 new Foo.getName();//2
14 new Foo().getName();//3
15 new new Foo().getName();//3
做这道题时,首先要明白一点:就是一开始的函数申明,function Foo(),在没有调用之前,始终是不会运行的.
1.Foo.getName()输出2!
此处函数Foo()没有调用,不执行函数,后面的输出均于此函数什么时候调用有密切关系.
此处的Foo是一个实例化对象,跟1行处的Foo除了同名再无其他关系.所以直接找到第5行处.这里第5行表示给Foo对象添加一个输出为2的方法.
2.getName()输出4.
此处直接调用getName(),1行处的函数未执行,从上往下寻找,首先找到
第7行处,定义的getName对象.
3.Foo().getName()输出1
此处先运行Foo(),这里就调用第1行的函数了,运行后return一个this,这里调用Foo()的是window,所以this就指window。后面相当于window.getName()就直接找到函数内部getName()方法了.
4.getName()输出1
因为在3中已经执行过Foo()函数了,函数内部内容有效.getName()无直接写明调用对象,此处调用的对象就是window,函数体内部,getName也并未重新定义,而是一个全局的getName(即window的方法),此处直接找到第二行处.
5.new Foo.getName()输出2
这里涉及到运算符的优先级别:’运算的()’>’.’> ‘new’||’函数调用的()’ 。
所以先执行5行处 Foo.getName()得到function(){console.log(2);}然后在 new function(){console.log(2);}
6.new Foo().getName()输出3
此处,先函数调用Foo(),接着运行new Foo(),再用new得到的这个实例化对象运行属性getName(),而getName()是通过6行处的原型链来定义的,所以找到第6行.
7.new new Foo().getName()输出3
此处有2个new,先执行右边的new Foo()得到一个实例化对象,这时,就无法运行左边的new了(总不至于new 后边跟一个实例对象吧),只能先运行后边的 .getName()得到一个函数,最后执行最左边的new.