1. 程式人生 > >一道考察運算子優先順序的JS面試題

一道考察運算子優先順序的JS面試題

文章目錄

最近遇到一個有意思的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操作符是對()貪婪的,遇到()它就立即執行,沒有遇到,它就等待。