摘要:有何區別在中,存在關鍵字,它聲明的變量同樣存在塊級作用域。而且函數本身的作用域,只存在其所在的塊級作用域之內,例如重復聲明一次函數上面這段代碼在中的輸出結果為因為被條件語句中的上升覆蓋了。如果對的使用,或的其他新特性感興趣,請自行閱讀文檔。
引子
首先大家看一下下面的代碼,猜猜會輸出什么結果?
var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar();
答案是10!
你是否會疑惑條件語句if(!foo)并不會執行,為什么foo會被賦值為10
再來看第二個例子
var a = 1; function b() { a = 10; return; function a() {} } b(); alert(a);
答案還是10嗎?顯然不是,alert輸出了1
如果你仍然對上面兩個輸出結果摸不著頭腦,那么請認真閱讀這篇文章
Scoping in JavascriptJavascript的作用域已經是老生常談的問題了,但是不一定每個人都能準確理解。
我們先來看一下C語言的一個例子:
#includeint main() { int x = 1; printf("%d, ", x); // 1 if (1) { int x = 2; printf("%d, ", x); // 2 } printf("%d ", x); // 1 }
程序依次輸出了1,2,1
為什么第三個輸出了1而不是2呢?因為在C語言中,我們有塊級作用域(block-level scope)。在一個代碼塊的中變量并不會覆蓋掉代碼塊外面的變量。我們不妨試一下Javascript中的表現
var x = 1; console.log(x); // 1 if (true) { var x = 2; console.log(x); // 2 } console.log(x); // 2
輸出的結果為1,2,2 if代碼塊中的變量覆蓋了全局變量。那是因為JavaScript是一種函數級作用域(function-level scope)所以if中并沒有獨立維護一個scope,變量x影響到了全局變量x
C,C++,C#和Java都是塊級作用域語言,那么在Javascript中,我們怎么實現一種類似塊級作用域的效果呢?答案是閉包
function foo() { var x = 1; if (x) { (function () { var x = 2; // some other code }()); } // x is still 1. }
上面代碼在if條件塊中創建了一個閉包,它是一個立即執行函數,所以相當于我們又創建了一個函數作用域,所以內部的x并不會對外部產生影響。
Hoisting in Javascript在Javascript中,變量進入一個作用域可以通過下面四種方式:
語言自定義變量:所有的作用域中都存在this和arguments這兩個默認變量
函數形參:函數的形參存在函數作用域中
函數聲明:function foo() {}
變量定義:var foo
其中,___在代碼運行前,函數聲明和變量定義通常會被解釋器移動到其所在作用域的最頂部___,如何理解這句話呢?
function foo() { bar(); var x = 1; }
上面這段在嗎,被代碼解釋器編譯完后,將變成下面的形式:
function foo() { var x; bar(); x = 1; }
我們注意到,x變量的定義被移動到函數的最頂部。然后在bar()后,再對其進行賦值。
再來看一個例子,下面兩段代碼其實是等價的:
function foo() { if (false) { var x = 1; } return; var y = 1; }
function foo() { var x, y; if (false) { x = 1; } return; y = 1; }
所以變量的上升(Hoisting)只是其定義上升,而變量的賦值并不會上升。
我們都知道,創建一個函數的方法有兩種,一種是通過函數聲明function foo(){}
另一種是通過定義一個變量var foo = function(){} 那這兩種在代碼執行上有什么區別呢?
來看下面的例子:
function test() { foo(); // TypeError "foo is not a function" bar(); // "this will run!" var foo = function () { // function expression assigned to local variable "foo" alert("this won"t run!"); } function bar() { // function declaration, given the name "bar" alert("this will run!"); } } test();
在這個例子中,foo()調用的時候報錯了,而bar能夠正常調用
我們前面說過變量會上升,所以var foo首先會上升到函數體頂部,然而此時的foo為undefined,所以執行報錯。而對于函數bar, 函數本身也是一種變量,所以也存在變量上升的現象,但是它是上升了整個函數,所以bar()才能夠順利執行。
再回到一開始我們提出的兩個例子,能理解其輸出原理了嗎?
var foo = 1; function bar() { if (!foo) { var foo = 10; } alert(foo); } bar();
其實就是:
var foo = 1; function bar() { var foo; if (!foo) { foo = 10; } alert(foo); } bar();
var a = 1; function b() { a = 10; return; function a() {} } b(); alert(a);
其實就是:
var a = 1; function b() { function a() {} a = 10; return; } b(); alert(a);
這就是為什么,我們寫代碼的時候,變量定義總要寫在最前面。
ES6有何區別在ES6中,存在let關鍵字,它聲明的變量同樣存在塊級作用域。
而且函數本身的作用域,只存在其所在的塊級作用域之內,例如:
function f() { console.log("I am outside!"); } if(true) { // 重復聲明一次函數f function f() { console.log("I am inside!"); } } f();
上面這段代碼在ES5中的輸出結果為I am inside!因為f被條件語句中的f上升覆蓋了。
在ES6中的輸出是I am outside!塊級中定義的函數不會影響外部。
如果對let的使用,或ES6的其他新特性感興趣,請自行閱讀ES6文檔。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/85885.html
摘要:依然持有對該作用域的引用,而這個引用就叫作閉包。循環和閉包正常情況下,我們對這段代碼行為的預期是分別輸出數字,每秒一次,每次一個。 一、作用域 作用域共有兩種主要的工作模型:第一種是最為普遍的,被大多數編程語言所采用的詞法作用域,另外一種叫作動態作用域; JavaScript所采用的作用域模式是詞法作用域。 1.詞法作用域 詞法作用域意味著作用域是由書寫代碼時函數聲明的位置來決定...
摘要:依然持有對該作用域的引用,而這個引用就叫作閉包。循環和閉包正常情況下,我們對這段代碼行為的預期是分別輸出數字,每秒一次,每次一個。 一、作用域 作用域共有兩種主要的工作模型:第一種是最為普遍的,被大多數編程語言所采用的詞法作用域,另外一種叫作動態作用域; JavaScript所采用的作用域模式是詞法作用域。 1.詞法作用域 詞法作用域意味著作用域是由書寫代碼時函數聲明的位置來決定...
摘要:作用域的類別可以影響到變量的取值,分為詞法作用域靜態作用域和動態作用域。而,采用的就是詞法作用域,或者叫靜態作用域。 關于javascript中的作用域和作用域鏈 我GitHub上的菜鳥倉庫地址: 點擊跳轉查看其他相關文章 文章在我的博客上的地址: 點擊跳轉 ? ? ? ? 前面的文章說到, 執行上下文的創建階段,主要有三個內容: ? ? ? ? 1、創建變量對象;2、初始化作用域...
摘要:寫在前面對于一個前端開發者,應該沒有不知道作用域的。欺騙詞法作用域有兩個機制可以欺騙詞法作用域和。關于你不知道的的第一部分作用域和閉包已經結束了,但是,更新不會就此止住未完待續 這是《你不知道的JavaScript》的第一部分。 本系列持續更新中,Github 地址請查閱這里。 寫在前面 對于一個前端開發者,應該沒有不知道作用域的。它是一個既簡單有復雜的概念,簡單到每行代碼都有它的影子...
摘要:大名鼎鼎的作用域和閉包,面試經常會問到。聲明理解閉包,先理解函數的執行過程。閉包的基本結構因為閉包不允許外界直接訪問,所以只能間接訪問函數內部的數據,獲得函數內部數據的使用權。 大名鼎鼎的作用域和閉包,面試經常會問到。閉包(closure)是Javascript語言的一個難點,也是它的特色。 聲明 理解閉包,先理解函數的執行過程。 代碼在執行的過程中會有一個預解析的過程,也就是在代碼的...
閱讀 3241·2021-11-24 10:43
閱讀 4203·2021-11-24 10:33
閱讀 3781·2021-11-22 09:34
閱讀 2131·2021-10-11 10:58
閱讀 3751·2021-10-11 10:58
閱讀 863·2021-09-27 13:36
閱讀 3583·2019-08-30 15:54
閱讀 2972·2019-08-29 18:41