一道考察運算子優先順序的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()
同上面,此時全域性的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
操作符是對()
貪婪的,遇到()它就立即執行,沒有遇到,它就等待。