摘要:全局變量函數內的局部作用域和是函數內的局部變量,而對的賦值將會覆蓋全局作用域內的同名變量。命名空間只有一個全局作用域導致的常見錯誤是命名沖突。另外兩種方式結論推薦使用匿名包裝器譯者注也就是自執行的匿名函數來創建命名空間。
盡管 JavaScript 支持一對花括號創建的代碼段,但是并不支持塊級作用域;
而僅僅支持 函數作用域。
function test() { // 一個作用域 for(var i = 0; i < 10; i++) { // 不是一個作用域 // count } console.log(i); // 10 }
注意: 如果不是在賦值語句中,而是在 return 表達式或者函數參數中,{...} 將會作為代碼段解析,
而不是作為對象的字面語法解析。如果考慮到 自動分號插入,這可能會導致一些不易察覺的錯誤。
譯者注:如果 return 對象的左括號和 return 不在一行上就會出錯。
// 譯者注:下面輸出 undefined function add(a, b) { return a + b; } console.log(add(1, 2));
JavaScript 中沒有顯式的命名空間定義,這就意味著所有對象都定義在一個全局共享的命名空間下面。
每次引用一個變量,JavaScript 會向上遍歷整個作用域直到找到這個變量為止。
如果到達全局作用域但是這個變量仍未找到,則會拋出 ReferenceError 異常。
// 腳本 A foo = "42"; // 腳本 B var foo = "42"
上面兩段腳本效果不同。腳本 A 在全局作用域內定義了變量 foo,而腳本 B 在當前作用域內定義變量 foo。
再次強調,上面的效果完全不同,不使用 var 聲明變量將會導致隱式的全局變量產生。
// 全局作用域 var foo = 42; function test() { // 局部作用域 foo = 21; } test(); foo; // 21
在函數 test 內不使用 var 關鍵字聲明 foo 變量將會覆蓋外部的同名變量。
起初這看起來并不是大問題,但是當有成千上萬行代碼時,不使用 var 聲明變量將會帶來難以跟蹤的 BUG。
// 全局作用域 var items = [/* 數組 */]; for(var i = 0; i < 10; i++) { subLoop(); } function subLoop() { // subLoop 函數作用域 for(i = 0; i < 10; i++) { // 沒有使用 var 聲明變量 // 干活 } }
外部循環在第一次調用 subLoop 之后就會終止,因為 subLoop 覆蓋了全局變量 i。
在第二個 for 循環中使用 var 聲明變量可以避免這種錯誤。
聲明變量時絕對不要遺漏 var 關鍵字,除非這就是期望的影響外部作用域的行為。
JavaScript 中局部變量只可能通過兩種方式聲明,一個是作為函數參數,另一個是通過 var 關鍵字聲明。
// 全局變量 var foo = 1; var bar = 2; var i = 2; function test(i) { // 函數 test 內的局部作用域 i = 5; var foo = 3; bar = 4; } test(10);
foo 和 i 是函數 test 內的局部變量,而對 bar 的賦值將會覆蓋全局作用域內的同名變量。
變量聲明提升(Hoisting)JavaScript 會提升變量聲明。這意味著 var 表達式和 function 聲明都將會被提升到當前作用域的頂部。
bar(); var bar = function() {}; var someValue = 42; test(); function test(data) { if (false) { goo = 1; } else { var goo = 2; } for(var i = 0; i < 100; i++) { var e = data[i]; } }
上面代碼在運行之前將會被轉化。JavaScript 將會把 var 表達式和 function 聲明提升到當前作用域的頂部。
// var 表達式被移動到這里 var bar, someValue; // 缺省值是 "undefined" // 函數聲明也會提升 function test(data) { var goo, i, e; // 沒有塊級作用域,這些變量被移動到函數頂部 if (false) { goo = 1; } else { goo = 2; } for(i = 0; i < 100; i++) { e = data[i]; } } bar(); // 出錯:TypeError,因為 bar 依然是 "undefined" someValue = 42; // 賦值語句不會被提升規則(hoisting)影響 bar = function() {}; test();
沒有塊級作用域不僅導致 var 表達式被從循環內移到外部,而且使一些 if 表達式更難看懂。
在原來代碼中,if 表達式看起來修改了全部變量 goo,實際上在提升規則被應用后,卻是在修改局部變量。
如果沒有提升規則(hoisting)的知識,下面的代碼看起來會拋出異常 ReferenceError。
// 檢查 SomeImportantThing 是否已經被初始化 if (!SomeImportantThing) { var SomeImportantThing = {}; }
實際上,上面的代碼正常運行,因為 var 表達式會被提升到全局作用域的頂部。
var SomeImportantThing; // 其它一些代碼,可能會初始化 SomeImportantThing,也可能不會 // 檢查是否已經被初始化 if (!SomeImportantThing) { SomeImportantThing = {}; }
譯者注:在 Nettuts+ 網站有一篇介紹 hoisting 的文章,其中的代碼很有啟發性。
// 譯者注:來自 Nettuts+ 的一段代碼,生動的闡述了 JavaScript 中變量聲明提升規則 var myvar = "my value"; (function() { alert(myvar); // undefined var myvar = "local value"; })();名稱解析順序
JavaScript 中的所有作用域,包括全局作用域,都有一個特別的名稱 this 指向當前對象。
函數作用域內也有默認的變量 arguments,其中包含了傳遞到函數中的參數。
比如,當訪問函數內的 foo 變量時,JavaScript 會按照下面順序查找:
當前作用域內是否有 var foo 的定義。
函數形式參數是否有使用 foo 名稱的。
函數自身是否叫做 foo。
回溯到上一級作用域,然后從 #1 重新開始。
命名空間注意: 自定義 arguments 參數將會阻止原生的 arguments 對象的創建。
只有一個全局作用域導致的常見錯誤是命名沖突。在 JavaScript中,這可以通過 匿名包裝器 輕松解決。
(function() { // 函數創建一個命名空間 window.foo = function() { // 對外公開的函數,創建了閉包 }; })(); // 立即執行此匿名函數
匿名函數被認為是 表達式;因此為了可調用性,它們首先會被執行。
( // 小括號內的函數首先被執行 function() {} ) // 并且返回函數對象 () // 調用上面的執行結果,也就是函數對象
有一些其他的調用函數表達式的方法,比如下面的兩種方式語法不同,但是效果一模一樣。
// 另外兩種方式 +function(){}(); (function(){}());結論
推薦使用匿名包裝器(譯者注:也就是自執行的匿名函數)來創建命名空間。這樣不僅可以防止命名沖突,
而且有利于程序的模塊化。
另外,使用全局變量被認為是不好的習慣。這樣的代碼傾向于產生錯誤和帶來高的維護成本。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/85349.html
摘要:不同的是函數體并不會再被提升至函數作用域頭部,而僅會被提升到塊級作用域頭部避免全局變量在計算機編程中,全局變量指的是在所有作用域中都能訪問的變量。 ES6 變量作用域與提升:變量的生命周期詳解從屬于筆者的現代 JavaScript 開發:語法基礎與實踐技巧系列文章。本文詳細討論了 JavaScript 中作用域、執行上下文、不同作用域下變量提升與函數提升的表現、頂層對象以及如何避免創建...
在之前的介紹中,我們已經知道 Javascript 沒有塊級作用,只有函數級作用域。 function test() { // a scope for(var i = 0; i < 10; i++) { // not a scope // count } console.log(i); // 10 } Javascript 中也沒有顯示的命名空間,這就...
摘要:是詞法作用域工作模式。使用可以將變量綁定在所在的任意作用域中通常是內部,也就是說為其聲明的變量隱式的劫持了所在的塊級作用域。 作用域與閉包 如何用js創建10個button標簽,點擊每個按鈕時打印按鈕對應的序號? 看到上述問題,如果你能看出來這個問題實質上是考對作用域的理解,那么恭喜你,這篇文章你可以不用看了,說明你對作用域已經理解的很透徹了,但是如果你看不出來這是一道考作用域的題目,...
閱讀 1142·2019-08-30 12:44
閱讀 650·2019-08-29 13:03
閱讀 2558·2019-08-28 18:15
閱讀 2427·2019-08-26 10:41
閱讀 3088·2019-08-26 10:28
閱讀 3037·2019-08-23 16:54
閱讀 1991·2019-08-23 15:16
閱讀 814·2019-08-23 14:55