启事
开通文章是为了能够有个处所长篇大论本日碰到的题目
由于提了一个题目(见 这里),被人讽刺。然则这个讽刺我的人(@xiaoboost )的答案并不对,他的答案只是依据效果诠释能够得出这个效果的实行。至于为何以及JavaScript在实行过程当中举行了哪些推断并没有举行细致的诠释或者说完全的诠释。其他的几个朋侪要么蔑视这道题、要么蔑视我把运算符优先级牵涉进来。最使我疑惑的是人人都以为这内里不牵涉到运算符的优先级推断。
在此,我以自身的明白来诠释一下JavaScript在实行过程当中举行了哪些推断和操纵。
原始题目:
function Foo() {
getName = function () {
alert(1);
};
return this;
}
Foo.getName = function () {
alert(2);
};
Foo.prototype.getName = function () {
alert(3);
};
var getName = function () {
alert(4);
};
function getName() {
alert(5);
}
Foo.getName();
getName()
Foo().getName()
getName()
new Foo.getName()
new Foo().getName()
new new Foo().getName()
我的答案:
起首,JS中会对变量声明和函数声明在编译阶段举行提拔,所以现实代码会表现成如许:
// 此处是变量提拔的演示,是在编译阶段举行的
var getName;
function Foo() {
getName = function () {
alert(1);
};
return this;
}
function getName() {
alert(5);
}
// 此处则只要到了实行阶段才会实行
Foo.getName = function () {
alert(2);
};
Foo.prototype.getName = function () {
alert(3);
};
getName = function () {
alert(4);
};
其次,除了第六问和第七问,一切有成员接见运算符(也叫属性接见器).
的表达式,.
的优先级都是最高,没有一个表达式有圆括号,有圆括号的要么是函数挪用,要么是new 运算(对象建立表达式)的构成部份。
这里特地申明没有圆括号是由于看到这个题目原作者自身的剖析文章将
new Foo().getName()
中的new Foo()
先实行诠释为由于圆括号的优先级高于.
。附上题目原作者自身的剖析文章:http://www.cnblogs.com/xxcang…
以下为各题目的数字输出以及为何:
第一问
2,直接挪用Foo函数的getName要领。
第二问
4,变量声明和函数声明会在编译阶段被提拔。此时,函数声明会掩盖变量声明。然则到了实行阶段,假如变量有赋值操纵,那末变量会因赋值而掩盖之前的函数声明。因而第二问的getName()
现实实行的是赋值了匿名函数function () {alert(4)}
的函数表达式。
第三问
1,.
运算符优先级最高,根据.
运算符的关联性从左往右先盘算左操纵数,Foo()
是一个函数挪用表达式,函数内部在实行时,由于函数内部没有查找到局部变量getName
,因而引擎会沿着作用域链向上查找getName
变量。在全局作用域中找到getName
变量(同时也是window
的属性/要领),给它赋值一个新的匿名函数function(){alert(1)}
。return
的this
此时指向当前要领所属的对象window
,因而,盘算右操纵数时,就是挪用了window
对象上的getName
要领。而前面左操纵数Foo()
中已给getName
变量从新赋值了一个匿名函数,因而会涌现新赋值函数所弹出的数字1。
第四问
1,getName()
已由于前面的Foo()
的挪用而赋值了新的匿名函数,因而弹出数字1。
第五问
2,new
能够与Foo
连系构成一个没有参数的对象建立表达式,然则如许它的优先级低于’.’,因而这里.
运算符优先级高于new
和函数挪用()
,全部表达式则能够明白为:new (Foo.getName)()
,当Foo.getName
实行终了会返回一个匿名函数function(){alert(2)}
,此时会与new
运算符、()
构成一个新的表达式:new function(){alert(2)}()
,这是一个对象建立表达式,这个表达式在实行实行的时刻,组织函数部份function(){alert(2)}
会被实行,效果就是2。别的,对象建立表达式在没有传入参数的情况下能够省略括号,因而原题中的new Foo.getName();
能够把背面的括号省略掉new Foo.getName
,效果一样。
第六问
3,带有参数的对象建立表达式(new constructor())和成员接见表达式的优先级是一样,这里就牵涉到应当明白成(new Foo()).getName()
照样new (Foo().getName)()
。假如是new (Foo().getName)()
,那末在实行Foo()时,它是一个函数挪用,优先级低于带参数的new,因而如许不可。那末只能是(new Foo()).getName()
。new Foo()
实例化一个对象,然后经由过程.
接见getName
属性,对象自身没有这个属性,顺着原型链查找到Foo.prototype
中有这个属性,而且赋值了一个匿名函数。末了经由过程函数挪用运算符挪用它,获得3。
第七问
3,能够看作 new((new Foo()).getName)()
,(new Foo()).getName
同上面的效果一样获得Foo.prototype.getName
一个匿名函数:function () {alert(3)}
,这个匿名函数与前面的new
以及背面的()
构成一个新的对象建立表达式new function () {alert(3)} ()
,这个表达式在实行时,会挪用个中的组织函数function (){alert(3)}
,因而会弹出3。
以上是我对这个题目的诠释,个中第六问获得@zonxin 的解答,再次谢谢,附上地点:https://segmentfault.com/q/10…
末了,附上我被讽刺而且被4个人’踩’的题目地点,假如以为我的解答是准确的,贫苦帮我’昭雪’╥﹏╥…;假如有毛病的处所,请留言指出,我会非常谢谢。
我的原题目地点:https://segmentfault.com/q/10…