詞法作用域 VS 動態作用域 VS 立即執行函式

2021-08-18 18:14:35 字數 2658 閱讀 7768

js詞法作用域是由你在寫**時將變數和塊作用域寫在**來決定。

js動態作用域和this機制息息相關。它的作用域詩是在執行的過程中確定

var a = 1;

function foo()

foo(); // 1

從上面的**,我們可以看出:foo中列印a的值不是由寫**的位置確定的,而是取決於foo執行的位置。

最小授權原則

最小授權原則是指在軟體設計中,應該最小限度地暴露必要內容,而將其他內容都「隱藏」起來,比如某個模組或物件的 api 設計。

這個原則可以延伸到如何選擇作用域來包含變數和函式。如果所有變數和函式都在全域性作 用域中,當然可以在所有的內部巢狀作用域中訪問到它們。但這樣會破壞前面提到的最小 特權原則,因為可能會暴漏過多的變數或函式,而這些變數或函式本應該是私有的,正確 的**應該是可以阻止對這些變數或函式進行訪問的。

例如:

function dosomething(a) 

function dosomethingelse(a)

var b;

dosomething( 2 ); // 15

在這個**片段中,變數 b 和函式 dosomethingelse(..) 應該是 dosomething(..) 內部具體 實現的「私有」內容。給予外部作用域對 b 和 dosomethingelse(..) 的「訪問許可權」不僅 沒有必要,而且可能是「危險」的,因為它們可能被有意或無意地以非預期的方式使用, 從而導致超出了 dosomething(..) 的適用條件。更「合理」的設計會將這些私有的具體內容隱藏在 dosomething(..) 內部,

例如:

function dosomething(a) 

var b;

b = a + dosomethingelse( a * 2 );

console.log( b * 3 );

}dosomething( 2 ); // 15

現在,b 和 dosomethingelse(..) 都無法從外部被訪問,而只能被 dosomething(..) 所控制。 功能性和最終效果都沒有受影響,但是設計上將具體內容私有化了,設計良好的軟體都會 依此進行實現。

規避衝突

當我們的程式**逐漸多起來,難免會出現變數衝突。那麼如何規避衝突就顯得額外重要。

函式可以把識別符號嚴謹的"隱藏"起來,外部無法訪問到,利用這個特性我們可以很好的規避衝突。

function foo() 

function bar()

foo和bar中定義了相同的變數a,但是卻不會相互造成影響。因為函式可以很好的把識別符號"隱藏"起來。

變數衝突的乙個典型例子存在於全域性作用域中。當程式中載入了多個第三方庫時,如果它 們沒有妥善地將內部私有的函式或變數隱藏起來,就會很容易引發衝突。

這些庫通常會在全域性作用域中宣告乙個名字足夠獨特的變數,通常是乙個物件。這個物件 被用作庫的命名空間,所有需要暴露給外界的功能都會成為這個物件(命名空間)的屬 性,而不是將自己的識別符號暴漏在頂級的詞法作用域中。

例如:

var mylibrary = 

}

立即執行函式(iife)

var a=2;

(function foo() )();

console.log( a ); // 2

函式名對 iife 當然不是必須的,iife 最常見的用法是使用乙個匿名函式表示式。雖然使 用具名函式的 iife 並不常見,但它具有以下優勢:

匿名函式在棧追蹤中不會顯示出有意義的函式名,使得除錯很困難。

如果沒有函式名,當函式需要引用自身時只能使用已經過期的arguments.callee引用, 比如在遞迴中。另乙個函式需要引用自身的例子,是在事件觸發後事件***需要解綁 自身。

匿名函式省略了對於**可讀性/可理解性很重要的函式名。乙個描述性的名稱可以讓 **不言自明。

因此具名函式的 iife 也是乙個值得推廣的實踐。

(function() ())
iife 也可以和其他形式的函式一樣實現引數的傳遞(多說一句:引數傳遞是按值傳遞)。

(function foo(a) )(3);
這個模式的另外乙個應用場景是解決 undefined 識別符號的預設值被錯誤覆蓋導致的異常(雖 然不常見)。將乙個引數命名為 undefined,但是在對應的位置不傳入任何值,這樣就可以 保證在**塊中 undefined 識別符號的值真的是 undefined:

undefined = true; // 給其他**挖了乙個大坑!絕對不要這樣做! 

(function iife( undefined )

})();

iife 還有一種變化的用途是倒置**的執行順序,將需要執行的函式放在第二位,在 iife 執行之後當作引數傳遞進去。儘管這種模式略顯冗長,但有些人認為它更易理解。

var a=2;

(function iife( def ) )(function def( global ) );

詞法作用域 vs 動態作用域

scheme是一門採用詞法作用域 lexical scoping 的lisp方言,這個設計是從alogol語言裡借鑑過來的。現在,詞法作用域已經被許多lisp方言所吸收,實踐表明,這的確是一項正確的設計,避免了很多奇怪的錯誤,比較符合人類的思維習慣。但是,在某些場合下,動態作用域又是很有用的特性,比...

詞法作用域和動態作用域

作用域是指程式源 中定義變數的區域。它規定了如何查詢變數,也是就確定當前執行 對變數的訪問許可權。js 採用了詞法作用域 lexical scoping 也就是靜態作用域。js 採用的詞法作用域是靜態作用域,因此函式的作用域在函式定義的時候就決定了。與靜態作用域相對的是動態作用域,函式的作用域是在函...

詞法作用域

域表示的就是 範圍,即 作用範圍.就是乙個名字在什麼地方可以被使用,什麼時候不能使用.所謂的 詞法 作用域,就是 在編寫過程中體現出來的作用範圍.一旦寫好,不用執行,作用範圍就已經確定好了.這個就是所謂詞法作用域.這意味著函式執行在定義它的作用域中,而不是在呼叫它的作用域中。在 js 中詞法作用域規...