激情欧美日韩一区二区,浪货撅高贱屁股求主人调教视频,精品无码成人片一区二区98,国产高清av在线播放,色翁荡息又大又硬又粗视频

JavaScript Scoping Hoisting解析

時(shí)間:2024-08-14 05:53:25 JavaScript 我要投稿
  • 相關(guān)推薦

JavaScript Scoping Hoisting解析

  Scoping & Hoisting

  var a = 1;function foo() { if (!a) { var a = 2; } alert(a);};foo();

  上面這段代碼在運行時(shí)會(huì )產(chǎn)生什么結果?

  盡管對于有經(jīng)驗的程序員來(lái)說(shuō)這只是小菜一碟,不過(guò)我還是順著(zhù)初學(xué)者常見(jiàn)的思路做一番描述:

  1.創(chuàng )建了全局變量 a,定義其值為 1

  2.創(chuàng )建了函數 foo

  3.在 foo 的函數體內,if 語(yǔ)句將不會(huì )執行,因為 !a 會(huì )將變量 a 轉變成布爾的假值,也就是 false

  4.跳過(guò)條件分支,alert 變量 a,最終的結果應該是輸出 1

  嗯,看起來(lái)無(wú)懈可擊的推理啊,但讓人驚訝的是:答案竟然是 2!為什么?

  別著(zhù)急,我會(huì )解釋給你聽(tīng)。首先我要告訴你這不是什么錯誤,而是 JavaScript 語(yǔ)言解釋器的一個(gè)(非官方的)特性,某人(Ben Cherry)把這個(gè)特性叫做:Hoisting(目前尚未有標準的翻譯,比較常見(jiàn)的是提升)。

  聲明與定義

  為了理解 Hoisting,我們先來(lái)看一個(gè)簡(jiǎn)單的情況:

  var a = 1;

  你是否想過(guò),上面這句代碼在運行的時(shí)候到底發(fā)生了什么?

  你是否知道,就這句代碼而言,“聲明變量 a” 和 “定義變量 a”這兩個(gè)說(shuō)法哪一個(gè)才是正確的?

  下例叫做 “聲明變量”:

  var a;

  下例叫做 “定義變量”:

  var a = 1;

  聲明:是指你聲稱(chēng)某樣東西的存在,比如一個(gè)變量或一個(gè)函數;但你沒(méi)有說(shuō)明這樣東西到底是什么,僅僅是告訴解釋器這樣東西存在而已;

  定義:是指你指明了某樣東西的具體實(shí)現,比如一個(gè)變量的值是多少,一個(gè)函數的函數體是什么,確切的表達了這樣東西的意義。

  總結一下:

  var a; // 這是聲明

  a = 1; // 這是定義(賦值)

  var a = 1; // 合二為一:聲明變量的存在并賦值給它

  重點(diǎn)來(lái)了:當你以為你只做了一件事情的時(shí)候(var a = 1),實(shí)際上解釋器把這件事情分解成了兩個(gè)步驟,一個(gè)是聲明(var a),另一個(gè)是定義(a = 1)。

  這和 Hoisting 有何關(guān)系?

  回到最開(kāi)始的那個(gè)令人困惑的例子,我告訴你解釋器是如何分析你的代碼的:

  var a;a = 1;function foo() { var a; // 關(guān)鍵在這里 if (!a) { a = 2; } alert(a); // 此時(shí)的 a 并非函數體外的那個(gè)全局變量}

  如代碼所示,在進(jìn)入函數體后解釋器聲明了新的變量 a,而無(wú)論 if 語(yǔ)句的條件如何,都將為新的變量 a 賦值為 2。你若不相信可以在函數體外面 alert(a),然后再執行 foo() 對比一下結果就知道了。

  Scoping(作用域)

  有人可能會(huì )問(wèn)了:“為什么不是在 if 語(yǔ)句內聲明變量 a?”

  因為 JavaScript 沒(méi)有塊級作用域(Block Scoping),只有函數作用域(Function Scoping),所以說(shuō)不是看見(jiàn)一對花括號 {} 就代表產(chǎn)生了新的作用域,和 C 不一樣!

  當解析器讀到 if 語(yǔ)句的時(shí)候,它發(fā)現此處有一個(gè)變量聲明和賦值,于是解析器會(huì )將其聲明提升至當前作用域的頂部(這是默認行為,并且無(wú)法更改),這個(gè)行為就叫做 Hoisting。

  OK,大家都懂了,你懂了嗎……

  懂了不代表就會(huì )用了,就拿最開(kāi)始的例子來(lái)說(shuō),如果我就是想要 alert(a) 出那個(gè) 1 可咋整呢?

  創(chuàng )建新的作用域

  alert(a) 在執行的時(shí)候,會(huì )去尋找變量 a 的位置,它從當前作用域開(kāi)始向上(或者說(shuō)向外)一直查找到頂層作用域為止,若是找不到就報 undefined。

  因為在 alert(a) 的同級作用域里,我們再次聲明了本地變量 a,所以它報 2;所以我們可以把本地變量 a 的聲明向下(或者說(shuō)向內)移動(dòng),這樣 alert(a) 就找不到它了。

  記。篔avaScript 只有函數作用域!

  var a = 1;function foo() { if (!a) { (function() { // 這是上一篇說(shuō)到過(guò)的 IIFE,它會(huì )創(chuàng )建一個(gè)新的函數作用域 var a = 2; // 并且該作用域在 foo() 的內部,所以 alert 訪(fǎng)問(wèn)不到 }()); // 不過(guò)這個(gè)作用域可以訪(fǎng)問(wèn)上層作用域哦,這就叫:“閉包” }; alert(a);};foo();

  你或許在無(wú)數的 JavaScript 書(shū)籍和文章里讀到過(guò):“請始終保持作用域內所有變量的聲明放置在作用域的頂部”,現在你應該明白為什么有此一說(shuō)了吧?因為這樣可以避免 Hoisting 特性給你帶來(lái)的困擾(我不是很情愿這么說(shuō),因為 Hoisting 本身并沒(méi)有什么錯),也可以很明確的告訴所有閱讀代碼的人(包括你自己)在當前作用域內有哪些變量可以訪(fǎng)問(wèn)。但是,變量聲明的提升并非 Hoisting 的全部。在 JavaScript 中,有四種方式可以讓命名進(jìn)入到作用域中(按優(yōu)先級):

  1.語(yǔ)言定義的命名:比如 this 或者 arguments,它們在所有作用域內都有效且優(yōu)先級最高,所以在任何地方你都不能把變量命名為 this 之類(lèi)的,這樣是沒(méi)有意義的

  2.形式參數:函數定義時(shí)聲明的形式參數會(huì )作為變量被 hoisting 至該函數的作用域內。所以形式參數是本地的,不是外部的或者全局的。當然你可以在執行函數的時(shí)候把外部變量傳進(jìn)來(lái),但是傳進(jìn)來(lái)之后就是本地的了

  3.函數聲明:函數體內部還可以聲明函數,不過(guò)它們也都是本地的了

  4.變量聲明:這個(gè)優(yōu)先級其實(shí)還是最低的,不過(guò)它們也都是最常用的

  另外,還記得之前我們討論過(guò) 聲明 和 定義 的區別吧?當時(shí)我并沒(méi)有說(shuō)為什么要理解這個(gè)區別,不過(guò)現在是時(shí)候了,記。

  Hosting 只提升了命名,沒(méi)有提升定義

  這一點(diǎn)和我們接下來(lái)要講到的東西息息相關(guān),請看:

  函數聲明與函數表達式的差別

  先看兩個(gè)例子:

  function test() { foo(); function foo() { alert("我是會(huì )出現的啦……"); }}test();

  function test() { foo(); var foo = function() { alert("我不會(huì )出現的哦……"); }}test();

  同學(xué),在了解了 Scoping & Hoisting 之后,你知道怎么解釋這一切了吧?

  在第一個(gè)例子里,函數 foo 是一個(gè)聲明,既然是聲明就會(huì )被提升(我特意包裹了一個(gè)外層作用域,因為全局作用域需要你的想象,不是那么直觀(guān),但是道理是一樣的),所以在執行 foo() 之前,作用域就知道函數 foo 的存在了。這叫做函數聲明(Function Declaration),函數聲明會(huì )連通命名和函數體一起被提升至作用域頂部。

  然而在第二個(gè)例子里,被提升的僅僅是變量名 foo,至于它的定義依然停留在原處。因此在執行 foo() 之前,作用域只知道 foo 的命名,不知道它到底是什么,所以執行會(huì )報錯(通常會(huì )是:undefined is not a function)。這叫做函數表達式(Function Expression),函數表達式只有命名會(huì )被提升,定義的函數體則不會(huì )。

  尾記:Ben Cherry 的原文解釋的更加詳細,只不過(guò)是英文而已。我這篇是借花獻佛,主要是更淺顯的解釋給初學(xué)者聽(tīng),若要看更多的示例,請移步原作,謝謝。

【JavaScript Scoping Hoisting解析】相關(guān)文章:

對javascript的理解08-08

常用的JavaScript模式09-22

Javascript的this用法簡(jiǎn)述08-15

JavaScript學(xué)習筆記08-24

JavaScript 基礎教學(xué)09-29

JavaScript的課堂講解09-03

JavaScript常用方法匯總10-25

JavaScript數組常用方法介紹09-04

JavaScript中的with關(guān)鍵字07-24

高效編寫(xiě)JavaScript代碼的技巧08-25

激情欧美日韩一区二区,浪货撅高贱屁股求主人调教视频,精品无码成人片一区二区98,国产高清av在线播放,色翁荡息又大又硬又粗视频