摘要:模仿塊級作用域立即執行函數前言最近在細讀高級程序設計,對于我而言,中文版,書中很多地方一筆帶過,所以用自己所理解的,嘗試細致解讀下。語法如下這里是塊級作用域以上代碼定義并立即調用了一個匿名函數。
模仿塊級作用域-立即執行函數
前言:最近在細讀Javascript高級程序設計,對于我而言,中文版,書中很多地方一筆帶過,所以用自己所理解的,嘗試細致解讀下。如有紕漏或錯誤,會非常感謝您的指出。文中絕大部分內容引用自《JavaScript高級程序設計第三版》。
JavaScript沒有塊級作用域的概念(ES5中沒有)。這意味著在塊語句定義的變量,實際上是在函數中而非語句中創建的。
function outputNumbers(count) { for( var i = 0; i < count; i ++ ) { console.log(i); // 0,1,2,3,4,5,6,7,8,9 } console.log(i); //10 } outputNumbers(10);
在函數outputNumbers()中定義了一個for循環, 而變量i的初始值被設置為0。
在Java、C++等語言中,變量i只會在for循環的語句中有定義,循環一旦結束,變量i就會被銷毀。
可是在JavaScript中,變量只是定義在函數outputNumbers()的活動對象中的,因此從它有定義開始,就可以在函數內部隨處訪問它。
即使像下面這樣錯誤地重新聲明同一個變量,也不會改變它的值。
function outputNumbers(count) { // 注意變量提升 var i for(var i = 0; i < count; i++) { console.log(i); // 0, 1, 2, 4, 5, 6, 7, 8, 9 }; var i; console.log(i); // 10 } outputNumbers(10);
JavaScript從來不會告訴你是否多次聲明了同一個變量;
遇到這種情況,它只會對后續的聲明視而不見(不過,它會執行后續聲明中的變量初始化)。
匿名函數可以用來模仿塊級作用域并避免這個問題(其實就是立即執行函數), 一定要注意變量的生命周期,局部變量只在執行環境中存在,塊級作用域其實就是立即執行函數,即刻產生一個作用域,塊級作用域里面的變量只在塊級作用域里面,避免了變量污染,隔離出一個獨立的作用域(私有作用域)。
//語法如下 (function(){ //這里是塊級作用域 })()
以上代碼定義并立即調用了一個匿名函數。
將函數聲明包含在一對圓括號中,表示它實際上是一個函數表達式。
而緊隨其后的另一對圓括號會立即調用這個函數。
這種語法,確實很不好理解。
來看下下面的例子
var someFunction = function() { //這里是塊級作用域 }; someFunction();
這個例子先定義了一個函數,然后立即調用它。定義函數的方式是創建一個匿名函數,并把匿名函數賦值給變量someFunction。而調用函數的方式是在函數名稱后面添加一對圓括號,即someFunction()。那么我們可不可以,聲明函數和調用函數寫在一塊呢?
function(){ //這里是塊級作用域 }(); //出錯
這段代碼會導致語法錯誤,因為JavaScript將function關鍵字當做一個函數聲明的開始。而函數聲明后面不能跟圓括號。
如果我們在function關鍵字前面加一個運算符,這樣就不會讓JavaScript將function關鍵字當做函數聲明的開始。解析器,就會依次從左往右解析代碼。
//解析過程 運算符 => 函數聲明function => 調用() !function(){ console.log("hi"); }(); // "hi" +function(){ console.log("hello"); }(); // "hello" -function(){ console.log("World"); }(); // "World" (function(){ console.log("ciao"); })(); // "ciao"
無論在什么地方,只要臨時需要一些變量,就可以使用私有作用域。
function outputNumbers(count) { //立即執行函數,隔離出一個獨立的作用域,避免變量的污染 //同時也是一個閉包, 能訪問到外部函數中的count (function(){ for(var i= 0; i < count; i++) { console.log(i); } })(); console.log(i); // error } outputNumbers(10); // 0,1,2,3,4,5,6,7,8,9 //i is not defined
這種技術(使用私有作用域),經常在全局作用域使用。
**從而限制向全局作用域中添加過多的變量和函數。
因為會產生變量污染,私有作用域可以訪問到全局變量,而全局變量訪問不到私有作用域里面的變量。**
一般來說,我們都應該盡量少向全局作用域中添加變量和函數。
在一個由很多開發人員共同參與的大型應用程序中,過多的全局變量和函數很容易導致命名沖突。
而通過創建私有作用域,每個開發人員都可以使用自己的變量,又不必擔心搞亂全局作用域。
(function(){ var now = new Date(); if(now.getMonth() == 0 && now.getDate() == 1) { console.log("Happy New Year!"); } })();
把上面這段代碼放在全局作用域中,可以用來確定哪一天是1月1日。
如果到了這一天,就會向用戶顯示一條祝賀新年的信息。
其中的變量now現在是匿名函數中的局部變量,而我們不必在全局作用域中創建它。
這種做法可以減少閉包占用的內存問題,因為沒有指向匿名函數的引用。只要函數執行完畢,就可以立即銷毀其作用域鏈了。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/98849.html
摘要:指針指針指針重要的時期說三遍由于對象類型為指針引用在變量復制方面,基本類型和引用類型也有所不同。在瀏覽器中,全局執行環境被認為是對象。 javascript---Symbol類型, 引用類型, 作用域 javascript的引用類型, 即對象類型是我們最常用的的類型, 其中有許多讓我們需要注意的地方, 最新的 , ES6 的推出, 使得對象類型的屬性名不僅僅可以是字符串類型,還可是Si...
摘要:而閉包的妙處在于,當函數在執行完畢后它的活動對象不會被銷毀,因為匿名函數的作用域鏈仍然在引用函數的活動對象它的作用域鏈會被銷毀。 一、閉包 閉包是指有權訪問另一個函數作用域中的變量的函數。創建閉包的常用方式是,在一個函數內部創建另一個函數。 請看以下代碼:我們在createComparisonFunction函數里創建了一個閉包 function createComparisonFun...
摘要:遞歸閉包模仿塊級作用域私有變量小結在編程中,使用函數表達式可以無需對函數命名,從而實現動態編程。匿名函數也稱為拉姆達函數。函數聲明要求有名字,但函數表達式不需要。中的函數表達式和閉包都是極其有用的特性,利用它們可以實現很多功能。 1、遞歸 2、閉包 3、模仿塊級作用域 4、私有變量 5、小結 在JavaScript編程中,使用函數表達式可以無需對函數命名,從而實現動態編程。匿名函數也稱...
摘要:關于函數聲明他的一個重要特征就是函數聲明提升就是在執行代碼之前會先讀取函數聲明這意味著可以把函數聲明放到調用他的語句的后面將聲明放到了后面關于函數表達式創建一個匿名函數然后賦值給一個變量函數體可以返回一個匿名函數返回的函數可以賦值給一個變量 關于函數聲明 他的一個重要特征就是函數聲明提升,就是在執行代碼之前會先讀取函數聲明,這意味著可以把函數聲明放到調用他的語句的后面 sayHi();...
閱讀 1446·2021-09-10 11:27
閱讀 2401·2019-08-30 15:53
閱讀 1317·2019-08-30 13:10
閱讀 2969·2019-08-30 11:09
閱讀 1075·2019-08-29 17:23
閱讀 664·2019-08-29 17:05
閱讀 2943·2019-08-29 15:10
閱讀 2339·2019-08-29 13:22