摘要:函數(shù)提升在里有兩種方式創(chuàng)建函數(shù),通過函數(shù)聲明和函數(shù)表達式。函數(shù)聲明用指定的參數(shù)來定義函數(shù)。提示不要在中進行函數(shù)聲明。問題輸出兩個都是用函數(shù)聲明的函數(shù),將被提升到的局部作用域頂端。函數(shù)本身將作為函數(shù)聲明在全局范圍內(nèi)提升。
作者關(guān)于提升的話題,總共有兩篇。(后來又有一個討論篇),再次搬過來。水平有限,如果翻譯的不準確請包涵,并去看原文。下面開始:
這是我之前的關(guān)于“提升”的文章,標題為《用let,const來指導你的JavaScript變量提升》(中/英)的第二部分。因此在深入研究之前,請確保你已經(jīng)閱讀過第一部分。
之前我只討論過變量提升,是因為函數(shù)提升在JavaScript中與變量提升不同。它有自己的獨特方式。我將在這對函數(shù)進行擴展,以及在面試中面試官總會提問的“提升”(變量和函數(shù))的棘手問題。
希望通過完成這兩部分,你能真的在你的JavaScript檢查清單中劃掉它。
讓我們開始吧。
函數(shù)提升在JavaScript里有兩種方式創(chuàng)建函數(shù),通過函數(shù)聲明和函數(shù)表達式。那就看看這兩種方式是如何影響“提升”的。
函數(shù)聲明用指定的參數(shù)來定義函數(shù)。
語法:
function name(param1, param2, ...) { [statements] }
在JavaScript里,函數(shù)聲明提升函數(shù)定義。
因此,這些函數(shù)在被聲明之前便可以使用。
例子:
hoisted() // output: "Hoisted" function hoisted() { console.log("Hoisted") }
下面的例子,展示JavaScript編譯器如何看待上面的代碼:
// Hoisted code function hoisted() { console.log("Hoisted") }// Rest of the code hoisted() // output: "Hoisted"
如果你在全局作用域或者功能區(qū)作用域(在JavaScript里基本叫局部作用域)進行函數(shù)聲明,這個行為是真實的。
這非常有用,因為你能在代碼開頭使用高級邏輯,使其可讀與可理解。
提示:不要在“if/else”中進行函數(shù)聲明。
“function”關(guān)鍵字也能在一個表達式中定義一個函數(shù)。
語法:
const myFunction = function [name](param1, param2, ...) { [statements] }
函數(shù)名是可選的,因此可以是匿名函數(shù)。我們可以用箭頭函數(shù),如下所示:
const myFunction = (param1, param2, ...) => { [statements] }
在JavaScript里,函數(shù)表達式?jīng)]有被提升。
因此,你不能使用函數(shù)表達式在定義它們之前。
例子:
notHoisted() // TypeError: notHoisted is not a function const notHoisted = function() { console.log("foo") }
關(guān)于函數(shù)創(chuàng)建中“提升”的部分,以上所有這些都要記住。
現(xiàn)在來看看面試問題!
“提升”的不穩(wěn)定行為一直是面試過程中的熱門問題。用之前和現(xiàn)在這兩篇文章的知識,可以解答這個話題中的任何問題。
問題 1 :var a = 1; function b() { a = 10; return; function a() {} } b(); console.log(a);
輸出: 1, 這是為什么?! ?
這是因為“function a() {}”聲明被創(chuàng)建在“函數(shù)/局部”作用域中。這個新“a”函數(shù)在聲明和定義的時候被提升到它的封閉函數(shù)b的頂端。下面演示發(fā)生了什么:
var a = 1; function b() { // Hoisted function a() {} a = 10; return; } b(); console.log(a)
因此,賦值a=10;不能改變?nèi)肿饔糜騛的值,任然是1,而是將局部a從函數(shù)改為整數(shù)10。
如果聲明函數(shù)a不在這,那將輸出10。
function foo(){ function bar() { return 3; } return bar(); function bar() { return 8; } } alert(foo());
輸出:8
兩個bar都是用函數(shù)聲明的函數(shù),將被提升到foo的局部作用域頂端。
然而,返回8的bar()將晚于第一個返回3的提升。因此,這個返回8的函數(shù)將被執(zhí)行。
之后的場景:
function foo(){ //Hoisted before function bar() { return 3; } // Hoisted after function bar() { return 8; } return bar(); } alert(foo());問題 3:
function parent() { var hoisted = "I"m a variable"; function hoisted() { return "I"m a function"; } return hoisted(); } console.log(parent());
輸出:“類型錯誤:hoisted不是一個函數(shù)”
這個很詭異。函數(shù) vs 變量!我們來分析下。
我們都知道,說到變量提升,只有聲明被提升(值是“undefined”),而不是定義!
如果是函數(shù)聲明的方式聲明函數(shù),聲明和定義一并提升!
現(xiàn)在,如果是多個相同標識符聲明(變量和函數(shù)在同一作用域里)這樣的情況,這個變量的提升會直接忽略。
解釋器只聲明函數(shù)并提升它。
最終,這個聲明變量變量賦值被執(zhí)行(沒有被提升),且值分配給了被提升的函數(shù),值“I‘m a variable” ,
這是一個簡單的字符串而不是函數(shù)。于是報錯了!
這后面的場景重現(xiàn)了問題:
function parent() { // Function declaration hoisted with the definition function hoisted() { return "I"m a function"; } // Declaration ignored, assignment of a string hoisted = "I"m a variable"; return hoisted(); } console.log(parent());問題 4:
alert(foo()); function foo() { var bar = function() { return 3; }; return bar(); var bar = function() { return 8; }; }
輸出:3
這個簡單。函數(shù)foo()本身將作為函數(shù)聲明在全局范圍內(nèi)提升。在函數(shù)foo里面,是兩個明確的函數(shù)表達式的例子。
編譯器不會提前讀取第二個函數(shù)bar() (沒有提升)。第一個將被執(zhí)行并返回。
問題 5:var myVar = "foo";(function() { console.log("Original value was: " + myVar); var myVar = "bar"; console.log("New value is: " + myVar); })();
輸出: “Original value was: undefined”, “New value is: bar”
在這個例子中,全局變量myVar的值‘foo’出現(xiàn)在picture之外。這是因為變量myVar在函數(shù)作用域內(nèi)部聲明和定義,而且被提升到了IIFE的頂端,值是‘undefined’,他被首先記錄。然后將值“bar”分配并記錄下來。
這是我這里對JavaScript提升的總結(jié)。?
希望這兩篇(中/英)文章能對你有幫助。
如果你想學習箭頭函數(shù)和ES6其他相關(guān)的功能,請查看下面的文章。
Peace ??
至此,關(guān)于提升的兩篇文章結(jié)束了。后來一個讀者和作者就問題1和問題3產(chǎn)生了分歧。到時候也搬過來吧。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/90452.html
摘要:閉包是返回另一個函數(shù)并攜帶數(shù)據(jù)的函數(shù)。當程序的上下文和作用域發(fā)生變化時,也會發(fā)生相應(yīng)的變化。之所以是類型,是因為類的構(gòu)造函數(shù)它是類型的。如下這里的是一個回調(diào)函數(shù),當成功響應(yīng)請求時將執(zhí)行該回調(diào)函數(shù)。 譯者:前端小智 原文:medium.com/dev-bits/a-… 想閱讀更多優(yōu)質(zhì)文章請猛戳GitHub博客,一年百來篇優(yōu)質(zhì)文章等著你! 為了說明 JS 面試的復雜性,首先,請嘗試給出以下結(jié)果...
摘要:忍者級別的函數(shù)操作對于什么是匿名函數(shù),這里就不做過多介紹了。我們需要知道的是,對于而言,匿名函數(shù)是一個很重要且具有邏輯性的特性。通常,匿名函數(shù)的使用情況是創(chuàng)建一個供以后使用的函數(shù)。 JS 中的遞歸 遞歸, 遞歸基礎(chǔ), 斐波那契數(shù)列, 使用遞歸方式深拷貝, 自定義事件添加 這一次,徹底弄懂 JavaScript 執(zhí)行機制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機制,如果...
摘要:寫在前面對于一個前端開發(fā)者,應(yīng)該沒有不知道作用域的。欺騙詞法作用域有兩個機制可以欺騙詞法作用域和。關(guān)于你不知道的的第一部分作用域和閉包已經(jīng)結(jié)束了,但是,更新不會就此止住未完待續(xù) 這是《你不知道的JavaScript》的第一部分。 本系列持續(xù)更新中,Github 地址請查閱這里。 寫在前面 對于一個前端開發(fā)者,應(yīng)該沒有不知道作用域的。它是一個既簡單有復雜的概念,簡單到每行代碼都有它的影子...
摘要:雖然有著各種各樣的不同,但是相同的是,他們前端優(yōu)化不完全指南前端掘金篇幅可能有點長,我想先聊一聊閱讀的方式,我希望你閱讀的時候,能夠把我當作你的競爭對手,你的夢想是超越我。 如何提升頁面渲染效率 - 前端 - 掘金Web頁面的性能 我們每天都會瀏覽很多的Web頁面,使用很多基于Web的應(yīng)用。這些站點看起來既不一樣,用途也都各有不同,有在線視頻,Social Media,新聞,郵件客戶端...
閱讀 2442·2021-11-15 11:36
閱讀 1182·2019-08-30 15:56
閱讀 2248·2019-08-30 15:53
閱讀 1045·2019-08-30 15:44
閱讀 658·2019-08-30 14:13
閱讀 1002·2019-08-30 10:58
閱讀 482·2019-08-29 15:35
閱讀 1304·2019-08-29 13:58