摘要:所以,這次再分享一道稍微有難度的題目。首先運行全局的被覆蓋成輸出并且返回的此時代表的是。隨后相當于執行的那么輸出的實際就是被覆蓋。首先帶參數的操作符優先級最高,第一步劃分為第二步劃分為所以執行這個函數是對應的所以執行肯定輸出的是。
上次分享了一道題,大家反響不錯,很開心自己寫的東西有人愿意花時間去看,也給了自己莫大的鼓舞,其實做題雖然不比真正的編程,但是也能夠讓你發現一些你之前沒有注意到的語言層面的問題。所以,這次再分享一道稍微有難度的JavaScript題目。
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(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
請問上述代碼在瀏覽器環境下,輸出結果是多少?
揭曉一下最終答案:
2 4 1 1 2 3 3
前四道難度不是很大,主要是后三道,基本是全軍覆沒,感嘆實在是太繞了了。后面慢慢分析了一下,逐個講一下吧。
首先必須注意一個問題
function Foo() { getName = function () { console.log("1"); }; return this; }
在函數內部聲明的getName變量,前面是不帶有var、let,const的,所以其實根據LHS(這個的介紹可以去的我博客看一下關于LHS和RHS的總結),聲明的getName是在全局范圍內(也是就window)。
其次需要明確你是否知道下面代碼在瀏覽器中的執行結果:
var getName = function () { console.log("4"); }; function getName() { console.log(5); } getName();
上述代碼的執行結果是:4。原因是這樣的,var聲明的變量和函數聲明function都會被提升,但是函數聲明的提升的級別是比
var要高的,所以上面的代碼的實際執行結果是:
function getName() { console.log(5); } var getName = function () { console.log("4"); }; getName();
后一個函數表達式getName覆蓋了前面的函數聲明getName,實際執行的是函數表達式(也就是是為什么JavaScript永遠不會有函數重載這么一說了),所以輸出的是4。
首先我給下面的代碼添加一下必要的注釋:
//函數聲明 function Foo() { //全局變量 getName = function () { console.log("1"); }; return this; } //為函數添加屬性getName,其類型是Function,所以這里也可以看出來,Function也是一種Object Foo.getName = function () { console.log("2"); }; //為Foo的原型添加方法getName Foo.prototype.getName = function () { console.log("3"); }; var getName = function () { console.log("4"); }; function getName() { console.log(5); }
下面執行第一條語句:
Foo.getName();
函數Foo本身并沒有執行,執行的是函數的屬性getName,當然輸出的是:2.
接下來執行:
getName();
這是在全局范圍內執行了getName(),有兩條對應的getName的聲明,根據前面我們所提到的提升的級別來看實際執行是函數表達式:
var getName = function () { console.log("4"); };
所以輸出的是4。
接下來執行
Foo().getName();
首先看一下JavaScript的操作符優先級,從高到低排序
從上面可以看出來()與.優先級相同,所以Foo().getName()從左至右執行。首先運行Foo(),全局的getName被覆蓋成輸出console.log("1"),并且返回的this此時代表的是window。隨后相當于執行的window.getName(),那么輸出的實際就是1(被覆蓋)。
下面到了
getName();
這個不用說了,執行的還是:1(和上面一毛一樣)。
下面到了三個最難的部分:
new Foo.getName();
對于這條語句的執行,有兩種可能:
(new Foo).getName()
或
new (Foo.getName)()
但是我們根據操作符優先級表可以得知,其實上.操作符要比new優先級要高,所以實際執行的是第二種,所以是對
Foo.getName = function () { console.log("2"); };
函數執行了new操作,當然輸出的是2。
下面到了執行
new Foo().getName();
這個語句的可能性也有兩種:
(new Foo()).getName();
或者
new (Foo().getName)();
那么應該是那種的呢?原來我以為會是第二種的執行方式,后面通過瀏覽器調試發現真實的執行的方式是第一種。我看到題目的作者是這么解釋的:
首先看運算符優先級括號高于new。實際執行為(new Foo()).getName()。遂先執行Foo函數。
我覺得上面的解釋是有問題的,對比上面兩種執行方式,第一種是先執行new,然后執行的是.操作符,然后執行的是()。第二種是先執行了(),再執行的是.,最后執行new操作符。如果真的按照引用所說的用優先級的方式判別,其實恰恰應該執行的是第二種而不是第一種。
后來總算找到原因了,原來之前那個出現的比較多的JavaScript優先級的表并不完整,萬能的MDN給出了最權威的JavaScript優先級表運算符優先級
我列舉出最重要的部分(由高到低):
所以帶參數的new操作符是優先級最高的,這下就沒有問題了,執行順序確實應該是第一種。
那么按照(new Foo()).getName();來執行,情況就就很簡單了,(new Foo())返回了新生成的對象,該對象沒有getName()方法,所以在prototype中找到了getName()方法。所以輸出的是3。
勝利就在眼前,我們看一下最后一問。
new new Foo().getName();
和上一步一樣的方法,我們按照優先級表給分析一下這個語句到底是怎么執行的。
首先帶參數的new操作符優先級最高,第一步劃分為:
new (new Foo().getName)();
第二步劃分為:
new ((new Foo()).getName)();
所以執行(new Foo()).getName這個函數是對應的Foo.prototype.getName,所以執行new (Foo.prototype.getName)()肯定輸出的是3。
哈哈哈,這么難得題終于解決了,開心~總結一下吧,首先JavaScript知識最好去MDN去查,萬一別的地方寫錯了真的是害人不淺。其次,如果在寫代碼的時候還是少利用操作符優先級這種東西,一旦不明確的地方就立刻用(),代碼的可閱讀性真的是很重要!很重要!很重要!畢竟代碼還是給人看~
如果有寫的不正確的地方,歡迎大家指出,資歷深淺,請多指教。歡迎大家去圍觀我的博客呀~~http://mrerhu.github.io
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/86736.html
摘要:忍者秘籍一書中,對于柯里化的定義如下在一個函數中首先填充幾個參數然后再返回一個新函數的技術稱為柯里化。回到我們的題目本身,其實根據測試用例我們可以發現,函數的要求就是接受單一函數,例如但是與柯里化不同之處在于,柯里化返回的一個新函數。 歡迎大家再一次來到我的文章專欄:從面試題中我們能學到什么,各位同行小伙伴是否已經開始了悠閑的春節假期呢?在這里提前祝大家雞年大吉吧~哈哈,之前有人說...
摘要:函數式編程前端掘金引言面向對象編程一直以來都是中的主導范式。函數式編程是一種強調減少對程序外部狀態產生改變的方式。 JavaScript 函數式編程 - 前端 - 掘金引言 面向對象編程一直以來都是JavaScript中的主導范式。JavaScript作為一門多范式編程語言,然而,近幾年,函數式編程越來越多得受到開發者的青睞。函數式編程是一種強調減少對程序外部狀態產生改變的方式。因此,...
摘要:正如我標題所說,簡歷被拒。看了我簡歷之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享 目錄: 印象中的頭條 面試背景 準備面試 ...
摘要:正如我標題所說,簡歷被拒。看了我簡歷之后說頭條競爭激烈,我背景不夠,點到為止。。三準備面試其實從三月份投遞簡歷開始準備面試到四月份收,也不過個月的時間,但這都是建立在我過去一年的積累啊。 本文是 無精瘋 同學投稿的面試經歷 關注微信公眾號:進擊的java程序員K,即可獲取最新BAT面試資料一份 在此感謝 無精瘋 同學的分享目錄:印象中的頭條面試背景準備面試頭條一面(Java+項目)頭條...
摘要:微信公眾號記錄截圖記錄截圖目前關于這塊算法與數據結構的安排前。已攻略返回目錄目前已攻略篇文章。會根據題解以及留言內容,進行補充,并添加上提供題解的小伙伴的昵稱和地址。本許可協議授權之外的使用權限可以從處獲得。 Create by jsliang on 2019-07-15 11:54:45 Recently revised in 2019-07-15 15:25:25 一 目錄 不...
閱讀 637·2021-11-22 15:32
閱讀 2725·2021-11-19 09:40
閱讀 2320·2021-11-17 09:33
閱讀 1277·2021-11-15 11:36
閱讀 1874·2021-10-11 10:59
閱讀 1485·2019-08-29 16:41
閱讀 1788·2019-08-29 13:45
閱讀 2157·2019-08-26 13:36