文章目录
最近遇到一个有意思的js相关的题目,看了网上的一些讲解,感觉不是那么靠谱。自己查阅资料后,做了一下总结。
题目
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();//2
getName(); //4
Foo().getName(); //1
getName(); //1
new Foo.getName(); //2
new Foo().getName(); //3
new new Foo().getName(); //3
最后的输出结果,我已经在代码的注释中写了,下面我开始对这7个输出结果进行一一分析。
分析
1. Foo.getName()
这个很简单了,取的是构造函数Foo的getName属性
2 .getName
这里涉及到了变量提升的相关知识,我们把代码进行一下更改
var getName = function(){
console.log(4)
}
function getName(){
console.log(5)
}
更改如下
var getName;
function getName(){
console.log(5)
}
getName= function(){
console.log(4)
}
这样你就知道为啥会输出4了
3. Foo().getName()
Foo().getName()
会先执行左侧的Foo()
,执行的结果是返回this
,这个this
指向的就是window
,所以执行结果相当于window.getName()
。但是需要注意的是Foo()
的内部定义了一个全局变量getName
,它会覆盖函数外部的getName
,所以,window.getName()
实际执行的是Foo()
内部的getName()
,所以输出结果就是1。
4. getName()
同上面,此时全局的getName
是Foo()
内部的那个getName
,所以输出结果就是1。
5. new Foo.getName()
在讲解下面的这几个列子时,我们需要对操作符的优先级有一定的了解,这里是运算符优先级的传送门。
这里截取部分截图:
图中我们可以看到()
圆括号的优先级最高,其次就是.
点运算符。这里面有一点是需要特别注意的,那就是排在19的new (带参数列表)
和函数调用,以及排在18的new (无参数列表)
。
下面我们再来分析new Foo.getName()
的执行顺序:
- 执行Foo.getName,得到f
- 执行new f()
所以执行结果就是2, 你可以进行如下验证new (Foo.getName)()
6. new Foo().getName()
有了上面的运算符的优先级,我们再来看看这个列子
- new Foo()的到m, m是一个Foo的实例
- m.getName()
输出结果就是3, 你可以进行如下验证 ( ( new Foo() ).getName )()
7. new new Foo().getName()
- new Foo()得到m, 即new m.getName();
- m.getName得到函数f
- new f()
输出结果就是3。你可以进行如下验证new ( ( new Foo() ).getName )()
小结
看了我上面的解释你可能还是有所疑惑的,关键点在于这个new foo().getN()
和new foo.getN()
的区别。这里我说一下我个人的理解,new
运算符会优先匹配带()
的表达式。 比如new foo()
,因为new+foo+()
的优先级比new + foo
的优先级高,所以会执行new foo()
而不是(new foo)()
。你可以在上面的实例中测试一下(new Foo).getName()
的结果,肯定就是3啦。
根据上面的描述,我们再来看看列子7new new Foo().getName()
:
首先是.
运算符,先执行其左侧new new Foo()
,先执行new Foo()
得到实例对象foo
,然后表达式如下new foo.getName()
,此时左侧表达式只剩下new 操作符,但是new
操作符可以理解为对()
贪婪的,它不会立即执行new foo
,而是等待foo.getName
的执行结果f
,然后执行new f()
。
由此我的结论就是new
操作符是对()
贪婪的,遇到()它就立即执行,没有遇到,它就等待。