function OuterFn() { innerFn = function() { console.log(1); }; return this; } OuterFn.innerFn = function () { console.log(2);} OuterFn.prototype.innerFn = function () { console.log(3);} var innerFn = function() { console.log(4);} function innerFn() { console.log(5);}
//请写出以下输出结果 OuterFn.innerFn(); //2 innerFn(); //4 OuterFn().innerFn();//1 innerFn(); //1 new OuterFn.innerFn(); //2 new OuterFn().innerFn(); //3 new new OuterFn().innerFn(); //3
第1问
这里省略分析,一眼就可以看出来答案。
第2问
function OuterFn() { innerFn = function () { console.log(1); } return this; } var innerFn; //变量声明提升 function innerFn() { console.log(5);} //函数声明提升,覆盖了变量声明 OuterFn.innerFn = function () { console.log(2);}; OuterFn.prototype.innerFn = function () { console.log(3);}; innerFn = function () { console.log(4);}; //最终赋值覆盖上面的函数声明 innerFn();// 4
第3问
先执行了OuterFn函数,然后调用OuterFn函数的返回值对象的innerFn属性函数。
因为没有var声明,所以向上层作用域寻找,找到了innerFn,也就是第2问的console.log(4),于是console.log(1)覆盖console.log(4),修改了外层作用域变量。
此处若依然没有找到会一直向上查找到window对象,若window对象中也没有innerFn属性,就在window对象中创建一个innerFn变量。这里的this指向window,相当于执行了window.innerFn();
第4问
直接调用innerFn(),相当于window.innerFn(),因为第3问的OuterFn()执行时修改了innerFn,因此结果与第3问相同。
在分析下面问题前,先回顾一下运算符优先级。
():圆括号 .:成员访问符 new Fn():有参构造 Fn():函数调用 new Fn:无参调用
参考MDN运算符优先级表格,排名结果为:圆括号 > 成员访问符 == 有参构造 == 函数调用 > 无参构造
第5问
因为成员访问符优先级高于无参构造优先级,所以先计算OuterFn.innerFn,而不是new OuterFn;接着,由于有参构造和函数调用优先级相等,那么顺序从左到右执行,相当于new (OuterFn.innerFn)()。
第6问
因为有参构造,成员访问符,函数调用优先级相等,那么顺序从左到右执行即可,相当于(new OuterFn()).innerFn()。
第7问
因为有参构造和成员访问符优先级相等,所以先计算new OuterFn();接着,由于无参构造优先级低于成员访问符,所以先计算后面,(new OuterFn()).innerFn;由于有参构造和函数调用优先级相等,那么顺序从左到右执行即可,相当于执行new ((new OuterFn()).innerFn)()。