下面这段代码的输出是什么?
Opened this issue · 3 comments
function Foo() {
getName = function() {console.log(1)};
return this;
}
Foo.getName = function() {console.log(2)};
Foo.prototype.getName = function() {console.log(3)};
var getName = function() {console.log(4)};
function getName() {console.log(5)};
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();
**说明:**一道经典的面试题,仅是为了帮助大家回顾一下知识点,加深理解,真实工作中,是不可能这样写代码的,否则,肯定会被打死的。
1.首先预编译阶段,变量声明与函数声明提升至其对应作用域的最顶端。
因此上面的代码编译后如下(函数声明的优先级先于变量声明):
function Foo() {
getName = function() {console.log(1)};
return this;
}
var getName;
function getName() {console.log(5)};
Foo.getName = function() {console.log(2)};
Foo.prototype.getName = function() {console.log(3)};
getName = function() {console.log(4)};
2.Foo.getName()
;直接调用Foo上getName方法,输出2
3.getName()
;输出4,getName被重新赋值了
4.Foo().getName()
;执行Foo(),window的getName被重新赋值,返回this;浏览器环境中,非严格模式,this 指向 window,this.getName();输出为1.
如果是严格模式,this 指向 undefined,此处会抛出错误。
如果是node环境中,this 指向 global,node的全局变量并不挂在global上,因为global.getName对应的是undefined,不是一个function,会抛出错误。
5.getName()
;已经抛错的自然走不动这一步了;继续浏览器非严格模式;window.getName被重新赋过值,此时再调用,输出的是1
6.new Foo.getName()
;考察运算符优先级的知识,new 无参数列表,对应的优先级是18;成员访问操作符 .
, 对应的优先级是 19。因此相当于是 new (Foo.getName)()
;new操作符会执行构造函数中的方法,因此此处输出为 2.
7.new Foo().getName()
;new 带参数列表,对应的优先级是19,和成员访问操作符.
优先级相同。同级运算符,按照从左到右的顺序依次计算。new Foo()
先初始化 Foo 的实例化对象,实例上没有getName方法,因此需要原型上去找,即找到了 Foo.prototype.getName
,输出3
8.new new Foo().getName()
; new 带参数列表,优先级19,因此相当于是 new (new Foo()).getName()
;先初始化 Foo 的实例化对象,然后将其原型上的 getName 函数作为构造函数再次 new ,输出3
因此最终结果如下:
Foo.getName(); //2
getName();//4
Foo().getName();//1
getName();//1
new Foo.getName();//2
new Foo().getName();//3
new new Foo().getName();//3
小姐姐对知识点的理解真透彻 很强~
小姐姐厉害,看了很多你的文章,很有帮助