一道考察运算符优先级的JS面试题

版权声明:本文为博主原创文章,评论区告知一声,大家随意转载! https://blog.csdn.net/MessageBox_/article/details/82907394

最近遇到一个有意思的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()

同上面,此时全局的getNameFoo()内部的那个getName,所以输出结果就是1。

5. new Foo.getName()

在讲解下面的这几个列子时,我们需要对操作符的优先级有一定的了解,这里是运算符优先级的传送门

这里截取部分截图:
avatar

图中我们可以看到()圆括号的优先级最高,其次就是.点运算符。这里面有一点是需要特别注意的,那就是排在19的new (带参数列表)和函数调用,以及排在18的new (无参数列表)

下面我们再来分析new Foo.getName()的执行顺序:

  1. 执行Foo.getName,得到f
  2. 执行new f()

所以执行结果就是2, 你可以进行如下验证new (Foo.getName)()

6. new Foo().getName()

有了上面的运算符的优先级,我们再来看看这个列子

  1. new Foo()的到m, m是一个Foo的实例
  2. m.getName()

输出结果就是3, 你可以进行如下验证 ( ( new Foo() ).getName )()

7. new new Foo().getName()
  1. new Foo()得到m, 即new m.getName();
  2. m.getName得到函数f
  3. 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操作符是对()贪婪的,遇到()它就立即执行,没有遇到,它就等待。

猜你喜欢

转载自blog.csdn.net/MessageBox_/article/details/82907394