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