国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

細(xì)說 Javascript 函數(shù)篇(六) : ?作用域與命名空間

VishKozus / 848人閱讀

在之前的介紹中,我們已經(jīng)知道 Javascript 沒有塊級作用,只有函數(shù)級作用域。

function test() { // a scope
    for(var i = 0; i < 10; i++) { // not a scope
        // count
    }
    console.log(i); // 10
}

Javascript 中也沒有顯示的命名空間,這就意味著一切都定義在全局作用域中。每一次引用一個變量時,Javascript 會往上遍歷整個全局作用域直到找到該變量。如果遍歷完整個全局作用域仍然沒有找到該變量,則拋出一個 ReferenceError 錯誤。

隱式全局變量
// script A
foo = "42";

// script B
var foo = "42"

上面的兩個例子產(chǎn)生不一樣的效果。第一個將在全局作用域中定義變量 foo,而第二個則在當(dāng)前作用域定義變量 foo。
我們一定要注意,如果不使用關(guān)鍵字 var 將會帶來意想不到的影響。

// global scope
var foo = 42;
function test() {
    // local scope
    foo = 21;
}
test();
foo; // 21

由于在函數(shù) test 內(nèi)沒用 var 來定義變量 foo,所以將覆蓋函數(shù)外部的全局變量 foo。盡管看上去不是什么大問題,但是如果有成千上萬行代碼時,這將是個難以追蹤的 bug。

// global scope
var items = [/* some list */];
for(var i = 0; i < 10; i++) {
    subLoop();
}

function subLoop() {
    // scope of subLoop
    for(i = 0; i < 10; i++) { // missing var statement
        // do amazing stuff!
    }
}

上例中,外部的循環(huán)將會在執(zhí)行第一次的時候就停止,這是因為 subloop 函數(shù)內(nèi)部的變量 i 將會覆蓋外部的全局變量 i。我們只需要在函數(shù)內(nèi)部加上一個 var 就可以避免這個錯誤,所以我們在定義變量時一定不要忘記加上關(guān)鍵字 var。除非我們確實希望對外部的全局變量造成影響。

局部變量

Javascript 中局部變量只可以通過兩個方式產(chǎn)生,一是通過關(guān)鍵字 var 來聲明,一是作為函數(shù)的形參。

// global scope
var foo = 1;
var bar = 2;
var i = 2;

function test(i) {
    // local scope of the function test
    i = 5;

    var foo = 3;
    bar = 4;
}
test(10);

此時,函數(shù) test 內(nèi)部的變量 ifoo 是局部變量,而 bar 則會覆蓋外部的全局變量 bar。

提升(Hoisting)

Javascript 將會提升變量聲明,這就意味著 var 表達(dá)式和函數(shù)聲明都將被提升到作用域的頂部。

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];
    }
}

上面的代碼在運行之前, var 表達(dá)式和函數(shù) test 的聲明都將提升至頂部,因此程序?qū)⒄_\行并不會報錯。

// var statements got moved here
var bar, someValue; // default to "undefined"

// the function declaration got moved up too
function test(data) {
    var goo, i, e; // missing block scope moves these here
    if (false) {
        goo = 1;

    } else {
        goo = 2;
    }
    for(i = 0; i < 100; i++) {
        e = data[i];
    }
}

bar(); // fails with a TypeError since bar is still "undefined"
someValue = 42; // assignments are not affected by hoisting
bar = function() {};

test();

由于 Javascript 沒有塊級作用域,這不僅將提升 var 表達(dá)式,同時也會使得 if 結(jié)構(gòu)變得不夠直觀。
在上例中,盡管看上去 if 在對全局變量 goo 進(jìn)行操作,實際上,由于變量 goo 被提升,所以修改的是局部變量。
如果沒有對提升規(guī)則有所了解,你可能會認(rèn)為下面的代碼將會拋出 ReferenceError 錯誤。

// check whether SomeImportantThing has been initialized
if (!SomeImportantThing) {
    var SomeImportantThing = {};
}

當(dāng)然上面的代碼是沒有錯誤的,因為在代碼在運行前,var 表達(dá)式已經(jīng)被提升到頂部。

var SomeImportantThing;

// other code might initialize SomeImportantThing here, or not

// make sure it"s there
if (!SomeImportantThing) {
    SomeImportantThing = {};
}
  

這里要推薦下 @nightire 凡哥的博文 《理解 JavaScript(二)》,里面對提升的講解非常透徹。

名稱解析順序

當(dāng)嘗試在一個函數(shù)作用域內(nèi)訪問一個 foo 變量時,Javascript 將會按照下面的順序查找:

當(dāng)前作用域內(nèi)是否有 var foo 的定義。

函數(shù)形參中是否有 foo 變量。

函數(shù)自身的名稱是否為 foo。

跳到外層定義域,再從第一部開始查找起。

命名空間

一個最常見的問題就是命名沖突,這是因為 Javascript 只有一個全局作用域所帶來的。但這個問題可以通過匿名的外部函數(shù)解決。

(function() {
    // a self contained "namespace"

    window.foo = function() {
        // an exposed closure
    };

})(); // execute the function immediately

上例中的匿名函數(shù)被認(rèn)為是表達(dá)式,所以它們會被執(zhí)行。

( // evaluate the function inside the parentheses
function() {}
) // and return the function object
() // call the result of the evaluation

當(dāng)然我們也可以用其他方式來調(diào)用函數(shù)表達(dá)式,不同的結(jié)構(gòu),但是同樣的效果。

// A few other styles for directly invoking the 
!function(){}()
+function(){}()
(function(){}());
// and so on...
總結(jié)

建議大家使用匿名的外部函數(shù)來將代碼封裝到空間內(nèi),這樣不僅可以解決命名空間的沖突,同時也有利于程序的模塊化。
此外,使用全局變量不是一個好習(xí)慣,這將帶來高成本的維護(hù)代價而且容易產(chǎn)生錯誤。

參考

http://bonsaiden.github.io/JavaScript-Garden/#function.scopes

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/78064.html

相關(guān)文章

  • js作用域與命名空間

    摘要:全局變量函數(shù)內(nèi)的局部作用域和是函數(shù)內(nèi)的局部變量,而對的賦值將會覆蓋全局作用域內(nèi)的同名變量。命名空間只有一個全局作用域?qū)е碌某R婂e誤是命名沖突。另外兩種方式結(jié)論推薦使用匿名包裝器譯者注也就是自執(zhí)行的匿名函數(shù)來創(chuàng)建命名空間。 盡管 JavaScript 支持一對花括號創(chuàng)建的代碼段,但是并不支持塊級作用域; 而僅僅支持 函數(shù)作用域。 function test() { // 一個作用域 ...

    antyiwei 評論0 收藏0
  • ES6 變量作用域與提升:變量的生命周期詳解

    摘要:不同的是函數(shù)體并不會再被提升至函數(shù)作用域頭部,而僅會被提升到塊級作用域頭部避免全局變量在計算機編程中,全局變量指的是在所有作用域中都能訪問的變量。 ES6 變量作用域與提升:變量的生命周期詳解從屬于筆者的現(xiàn)代 JavaScript 開發(fā):語法基礎(chǔ)與實踐技巧系列文章。本文詳細(xì)討論了 JavaScript 中作用域、執(zhí)行上下文、不同作用域下變量提升與函數(shù)提升的表現(xiàn)、頂層對象以及如何避免創(chuàng)建...

    lmxdawn 評論0 收藏0
  • 前端基礎(chǔ)進(jìn)階(四):詳細(xì)圖解作用域鏈與閉包

    摘要:之前一篇文章我們詳細(xì)說明了變量對象,而這里,我們將詳細(xì)說明作用域鏈。而的作用域鏈,則同時包含了這三個變量對象,所以的執(zhí)行上下文可如下表示。下圖展示了閉包的作用域鏈。其中為當(dāng)前的函數(shù)調(diào)用棧,為當(dāng)前正在被執(zhí)行的函數(shù)的作用域鏈,為當(dāng)前的局部變量。 showImg(https://segmentfault.com/img/remote/1460000008329355);初學(xué)JavaScrip...

    aikin 評論0 收藏0
  • 細(xì)說 Javascript 函數(shù)(一) : 函數(shù)聲明和函數(shù)表達(dá)式

    摘要:函數(shù)表達(dá)式對于函數(shù)聲明,函數(shù)的名稱是必須的,而對于函數(shù)表達(dá)式而言則是可選的,因此,就出現(xiàn)了匿名函數(shù)表達(dá)式和命名函數(shù)表達(dá)式。這是因為對命名函數(shù)處理的機制,函數(shù)的名稱永遠(yuǎn)在函數(shù)內(nèi)部的作用域中有效。 function 是 Javascript 中的第一類對象,這就意味著函數(shù)可以像其他值一樣被傳遞。一個最常見的用法就是將一個匿名函數(shù)作為回調(diào)函數(shù)傳遞到另外一個異步函數(shù)中。 函數(shù)聲明 func...

    hizengzeng 評論0 收藏0
  • 先有蛋還是先有雞?JavaScript 作用域與閉包探析

    摘要:而閉包的神奇之處正是可以阻止事情的發(fā)生。拜所聲明的位置所賜,它擁有涵蓋內(nèi)部作用域的閉包,使得該作用域能夠一直存活,以供在之后任何時間進(jìn)行引用。依然持有對該作用域的引用,而這個引用就叫閉包。 引子 先看一個問題,下面兩個代碼片段會輸出什么? // Snippet 1 a = 2; var a; console.log(a); // Snippet 2 console.log(a); v...

    elisa.yang 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<