摘要:第七問,可以看做,同上面的結果一樣得到一個匿名函數,這個匿名函數與前面的以及后面的組成一個新的對象創建表達式,這個表達式在執行時,會調用其中的構造函數,因此會彈出。
緣由
開通文章是為了能夠有個地方長篇大論今天遇到的問題
由于提了一個問題(見 這里),被人嘲諷。但是這個嘲諷我的人(@xiaoboost )的答案并不對,他的答案只是根據結果解釋能夠得出這個結果的執行。至于為什么以及JavaScript在執行過程中進行了哪些判斷并沒有進行詳細的解釋或者說完整的解釋。其余的幾個朋友要么鄙視這道題、要么鄙視我把運算符優先級牽扯進來。最讓我納悶的是大家都認為這里面不牽扯到運算符的優先級判斷。
在此,我以自己的理解來解釋一下JavaScript在執行過程中進行了哪些判斷和操作。
function Foo() { getName = function () { alert(1); }; return this; } Foo.getName = function () { alert(2); }; Foo.prototype.getName = function () { alert(3); }; var getName = function () { alert(4); }; function getName() { alert(5); } Foo.getName(); getName() Foo().getName() getName() new Foo.getName() new Foo().getName() new new Foo().getName()我的答案:
首先,JS中會對變量聲明和函數聲明在編譯階段進行提升,所以實際代碼會表現成這樣:
// 此處是變量提升的演示,是在編譯階段進行的 var getName; function Foo() { getName = function () { alert(1); }; return this; } function getName() { alert(5); } // 此處則只有到了執行階段才會執行 Foo.getName = function () { alert(2); }; Foo.prototype.getName = function () { alert(3); }; getName = function () { alert(4); };
其次,除了第六問和第七問,所有有成員訪問運算符(也叫屬性訪問器).的表達式,.的優先級都是最高,沒有一個表達式有圓括號,有圓括號的要么是函數調用,要么是new 運算(對象創建表達式)的組成部分。
這里專門說明沒有圓括號是因為看到這個問題原作者自己的分析文章將new Foo().getName()中的new Foo()先執行解釋為由于圓括號的優先級高于.。附上問題原作者自己的分析文章:http://www.cnblogs.com/xxcang...
以下為各問題的數字輸出以及為什么:
第一問2,直接調用Foo函數的getName方法。
第二問4,變量聲明和函數聲明會在編譯階段被提升。此時,函數聲明會覆蓋變量聲明。但是到了執行階段,如果變量有賦值操作,那么變量會因賦值而覆蓋之前的函數聲明。因此第二問的getName()實際執行的是賦值了匿名函數function () {alert(4)}的函數表達式。
第三問1,.運算符優先級最高,按照.運算符的關聯性從左往右先計算左操作數,Foo()是一個函數調用表達式,函數內部在執行時,由于函數內部沒有查找到局部變量getName,因此引擎會沿著作用域鏈向上查找getName變量。在全局作用域中找到getName變量(同時也是window的屬性/方法),給它賦值一個新的匿名函數function(){alert(1)}。return的this此時指向當前方法所屬的對象window,因此,計算右操作數時,就是調用了window對象上的getName方法。而前面左操作數Foo()中已經給getName變量重新賦值了一個匿名函數,因此會出現新賦值函數所彈出的數字1。
第四問1,getName()已經因為前面的Foo()的調用而賦值了新的匿名函數,因此彈出數字1。
第五問2,new可以與Foo結合組成一個沒有參數的對象創建表達式,但是這樣它的優先級低于".",因此這里.運算符優先級高于new和函數調用(),整個表達式則可以理解為:new (Foo.getName)(),當Foo.getName執行完畢會返回一個匿名函數function(){alert(2)},此時會與new運算符、()組成一個新的表達式:new function(){alert(2)}(),這是一個對象創建表達式,這個表達式在執行執行的時候,構造函數部分function(){alert(2)}會被執行,結果就是2。另外,對象創建表達式在沒有傳入參數的情況下可以省略括號,因此原題中的new Foo.getName();可以把后面的括號省略掉new Foo.getName,結果一樣。
第六問3,帶有參數的對象創建表達式(new constructor())和成員訪問表達式的優先級是一樣,這里就牽扯到應該理解成
(new Foo()).getName()還是new (Foo().getName)()。如果是new (Foo().getName)(),那么在執行Foo()時,它是一個函數調用,優先級低于帶參數的new,因此這樣不行。那么只能是(new Foo()).getName()。new Foo()實例化一個對象,然后通過.訪問getName屬性,對象本身沒有這個屬性,順著原型鏈查找到Foo.prototype中有這個屬性,并且賦值了一個匿名函數。最后通過函數調用運算符調用它,得到3。
3,可以看做 new((new Foo()).getName)(),(new Foo()).getName同上面的結果一樣得到Foo.prototype.getName一個匿名函數:function () {alert(3)},這個匿名函數與前面的new以及后面的()組成一個新的對象創建表達式new function () {alert(3)} (),這個表達式在執行時,會調用其中的構造函數function (){alert(3)},因此會彈出3。
以上是我對這個問題的解釋,其中第六問得到@zonxin 的解答,再次感謝,附上地址:https://segmentfault.com/q/10...
最后,附上我被嘲諷并且被4個人"踩"的問題地址,如果覺得我的解答是正確的,麻煩幫我"平反"╥﹏╥...;如果有錯誤的地方,請留言指出,我會十分感謝。
我的原問題地址:https://segmentfault.com/q/10...
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/81681.html
摘要:面試會進入下一個環節。如果在頁面中有多個按鈕,那么這個彈出窗要如何實現同上,根據之前的建議在回答問題之前要問清楚問題中模棱兩可的地方。是否觸發不同按鈕彈出的窗口現實的內容不同。 這道面試題,當初我面試的時候被問過兩次,因此比較深,此外,我記得還有設計模式的考察,所以,有深刻的體會。 面試題主要考察什么 面試不是個輕松的活,不管是對面試官還是面試者都一樣。對于面試官來說,別的先不管,首先...
摘要:然后最外層這個函數會返回一個新對象,對象里面有一個屬性,名為,而這個屬性的值是一個匿名函數,它會返回。 最近看到一條有意思的閉包面試題,但是看到原文的解析,我自己覺得有點迷糊,所以自己重新做一下這條題目。 閉包面試題原題 function fun(n, o) { // ① console.log(o); return { // ② fun: function(m) ...
摘要:說明最近看到這樣一段代碼問三行的輸出分別是什么覺得有點意思,和大家一起來聊聊。說到這里,這道題基本上可以解決了,希望大家能聽明白我上面說的話,下面的就簡單了。 說明 最近看到這樣一段代碼 function fun(n,o){ console.log(o); return { fun:function(m){ return fun...
摘要:說明最近看到這樣一段代碼問三行的輸出分別是什么覺得有點意思,和大家一起來聊聊。說到這里,這道題基本上可以解決了,希望大家能聽明白我上面說的話,下面的就簡單了。 說明 最近看到這樣一段代碼 function fun(n,o){ console.log(o); return { fun:function(m){ return fun...
閱讀 1026·2021-11-22 13:53
閱讀 1577·2021-11-17 09:33
閱讀 2372·2021-10-14 09:43
閱讀 2835·2021-09-01 11:41
閱讀 2262·2021-09-01 10:44
閱讀 2904·2021-08-31 09:39
閱讀 1443·2019-08-30 15:44
閱讀 1853·2019-08-30 13:02