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

資訊專欄INFORMATION COLUMN

閉包全面詳解

qylost / 698人閱讀

摘要:環境由閉包創建時在作用域中的任何局部變量組成。嚴格來說,閉包需要滿足三個條件訪問所在作用域函數嵌套在所在作用域外被調用閉包的形成原理先了解的垃圾回收機制會找出不再使用的變量,不再使用意味著這個變量生命周期的結束。

什么是閉包 最原始定義

閉包(closure),是指函數變量可以保存在函數作用域內,因此看起來是函數將變量“包裹”了起來。

//根據定義,包含變量的函數就是閉包
function foo() {
    var a = 0;
}
cosole.log(a) 
// Uncaught ReferenceError: a is not defined
《JavaScript高級程序設計》對閉包定義

閉包是指有權訪問另一個函數作用域中的變量的函數

 //訪問上層函數的作用域的內層函數就是閉包
function foo() {
    var a = 2;
    function bar() {
        console.log(a);
    }
    bar();
}
foo();
《JavaScript權威指南》對閉包定義

函數對象可以通過作用域鏈相互關聯起來,函數體內部變量可以保存在函數作用域內,這就是閉包。

 var global = "global scope"; //全局變量
function checkscope() {
    var scope = "local scope"; //局部變量
    function f() {
        return scope; //在作用域中返回這個值
    };
    return f();
}
checkscope(); // 返回 "local scope"
《你不知道的JavaScript》這樣描述

當函數可以記住并訪問所在的詞法作用域時,就產生了閉包,即使函數是在當前詞法作用域之外執行。

//fn3就是fn2函數本身。執行fn3能正常輸出name
//這不就是fn2能記住并訪問它所在的詞法作用域,而且fn2函數的運行還是在當前詞法作用域之外了。
function fn1() {
    var name = "iceman";
    function fn2() {
        console.log(name);
    }
    return fn2;
}
var fn3 = fn1();
fn3();
MDN 上面這么說:

閉包是一種特殊的對象。它由兩部分構成:函數,以及創建該函數的環境。環境由閉包創建時在作用域中的任何局部變量組成。
簡單說就是指那些能夠訪問自由變量的函數。

嚴格來說,閉包需要滿足三個條件:

【1】訪問所在作用域;
【2】函數嵌套;
【3】在所在作用域外被調用

閉包的形成原理 先了解JavaScript的垃圾回收機制

Javascript 會找出不再使用的變量,不再使用意味著這個變量生命周期的結束。
Javascript 中存在兩種變量——全局變量和局部變量,全部變量的聲明周期會一直持續,直到頁面卸載而局部變量聲明在函數中,它的聲明周期從執行函數開始,直到函數執行結束。在這個過程中,局部變量會在堆或棧上被分配相應的空間以存儲它們的值,函數執行結束,這些局部變量也不再被使用,它們所占用的空間也就被釋放。
但是有一種情況的局部變量不會隨著函數的結束而被回收,那就是局部變量被函數外部的變量所使用,其中一種情況就是閉包,因為在函數執行結束后,函數外部的變量依然指向函數內的局部變量,此時的局部變量依然在被使用,所以也就不能夠被回收

var scope = "global scope";
function checkScope() {
    var scope = "local scope";
    return function() {
        console.log(scope);
    }
}

var result = checkScope(); 
result();   // local scope checkScope變量對象中的scope,非全局變量scope

此匿名函數的作用域鏈包括checkScope的活動對象和全局變量對象, 當checkScope函數執行完畢后,checkScope的活動對象并不會被銷毀,因為匿名函數的作用域鏈還在引用checkScope的活動對象,也就是checkScope的執行環境被銷毀,但是其活動對象沒有被銷毀,留存在堆內存中,直到匿名函數銷毀后,checkScope的活動對象才會銷毀

從作用域鏈理解閉包的形成

從理論角度:所有的函數。因為它們都在創建的時候就將上層上下文的數據保存起來了。哪怕是簡單的全局變量也是如此,因為函數中訪問全局變量就相當于是在訪問自由變量,這個時候使用最外層的作用域。

從實踐角度:以下函數才算是閉包:

i. 即使創建它的上下文已經銷毀,它仍然存在(比如,內部函數從父函數中返回)
ii. 在代碼中引用了自由變量

var scope = "global scope";
function checkscope(){
    var scope = "local scope";
    function f(){
        return scope;
    }
    return f;
}

var foo = checkscope();
foo();

fContext = {//f函數的執行上下文
    Scope: [AO, checkscopeContext.AO, globalContext.VO],
}

對的,就是因為這個作用域鏈,f函數在聲明的時候壓入了上層的變量對象,f 函數依然可以讀取到 checkscopeContext.AO 的值,并且如果當 f 函數引用了 checkscopeContext.AO 中的值的時候,即使 checkscopeContext 被銷毀了,但是 JavaScript 依然會讓 checkscopeContext.AO 活在內存中(和垃圾回收機制有關下文會說),f 函數依然可以通過 f 函數的作用域鏈找到它,正是因為 JavaScript 做到了這一點,從而實現了閉包這個概念。

閉包的作用-模仿塊級作用域,封裝私有變量
任何在函數中定義的變量,都可以認為是私有變量,因為不能在函數外部訪問這些變量。
私有變量包括函數的參數、局部變量和函數內定義的其他函數。
function module() {
    var arr = [];
    function add(val) {
        if (typeof val == "number") {
            arr.push(val);
        }
    }
    function get(index) {
        if (index < arr.length) {
            return arr[index]
        } else {
            return null;
        }
    }
    return {
        add: add,
        get: get
    }
}
var mod1 = module();
mod1.add(1);
mod1.add(2);
mod1.add("xxx");
console.log(mod1.get(2));//外部是無法直接拿到arr的只能通過get來拿
閉包的作用-使變量保存在內存中不被銷毀 實例1-計數器

我們來實現一個計數器,每調用一次計數器返回值加一:

var counter = 0;
function add() {
   return counter += 1;
}
add();
add();
add();// 計數器現在為 3 

問題:

全局變量容易被其他代碼改變

如果我需要同時用兩個計數器,但這種寫法只能滿足一個使用,另一個還想用的話就要再寫個counter2函數,再定義一個counter2的全局變量。

那我們把counter放在add函數里面不就好了么?

function add() {
    var counter = 0;
    return counter += 1;
} 
add();
add();
add();// 本意是想輸出 3, 但輸出的都是 1

所以這樣做的話,每次調用add函數,counter的值都要被初始化為0,還是達不到我們的目的。

使用閉包來寫就會解決這些問題

function add() {
    var index = 1;
    function counter() {
        return index ++;
    }
    return counter;
}

// test
var addA = add() ;
var addB = add() ;
addA();        // 1
addA();        // 2
addB();        // 1
addB();        // 2
實例2-延時打印

這樣打印出來的全部都是10,原因是for循環是同步的會在延時1000毫秒的過程中一直執行
等function執行的時候變量i指向的是同一個內存地址,且值已經變成的10

for (var i = 1; i <= 10; i++) {
    setTimeout(function () {
        console.log(i);
    }, 1000);
}

改進,用自執行的函數創建簡單的閉包,讓每一次for循環的i都在不同的內存地址中且不被銷毀

for (var i = 1; i <= 10; i++) {
    (function () {
        var j = i;
        setTimeout(function () {
            console.log(j);
        }, 1000);
    })();
}

優化寫法

for (var i = 1; i <= 10; i++) {
    (function (j) {
        setTimeout(function () {
            console.log(j);
        }, 1000);
    })(i);
}
聯系Static靜態變量

閉包的作用主要就是讓變量的值始終保持在內存中。
C++或C語言還有Java中都有static靜態變量也是讓變量始終保存在內存中。
這樣來看好像閉包好像有點static靜態變量的意思。

總結

閉包就是子函數可以有權訪問父函數的變量、父函數的父函數的變量、一直到全局變量。
歸根結底,就是利用js得詞法(靜態)作用域,即作用域鏈在函數創建的時候就確定了。
子函數如果不被銷毀,整條作用域鏈上的變量仍然保存在內存中,這樣就形成了閉包

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/106523.html

相關文章

  • JavaScript深入淺出

    摘要:理解的函數基礎要搞好深入淺出原型使用原型模型,雖然這經常被當作缺點提及,但是只要善于運用,其實基于原型的繼承模型比傳統的類繼承還要強大。中文指南基本操作指南二繼續熟悉的幾對方法,包括,,。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。 怎樣使用 this 因為本人屬于偽前端,因此文中只看懂了 8 成左右,希望能夠給大家帶來幫助....(據說是阿里的前端妹子寫的) this 的值到底...

    blair 評論0 收藏0
  • 深入理解JavaScript系列3:全面解析Module模式

    摘要:總結上面的大部分方式都可以互相組合使用的,一般來說如果要設計系統,可能會用到松耦合擴展,私有狀態和子模塊這樣的方式。 簡介 Module模式是JavaScript編程中一個非常通用的模式,一般情況下,大家都知道基本用法,本文嘗試著給大家更多該模式的高級使用方式。 首先我們來看看Module模式的基本特征: 模塊化,可重用 封裝了變量和function,和全局的namaspace不接觸...

    付倫 評論0 收藏0
  • Flutter 面試知識點集錦

    摘要:中的的線程是以事件循環和消息隊列的形式存在,包含兩個任務隊列,一個是內部隊列,一個是外部隊列,而的優先級又高于。同時還有處理按住時的事件額外處理,同時手勢處理一般在的子類進行。谷歌大會之后,有不少人咨詢了我 Flutter 相關的問題,其中有不少是和面試相關的,如今一些招聘上也開始羅列 Flutter 相關要求,最后想了想還是寫一期總結吧,也算是 Flutter 的階段復習。 ??系統完...

    andong777 評論0 收藏0
  • 【進階2-2期】JavaScript深入之從作用域鏈理解閉包

    摘要:使用上一篇文章的例子來說明下自由變量進階期深入淺出圖解作用域鏈和閉包訪問外部的今天是今天是其中既不是參數,也不是局部變量,所以是自由變量。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第二期,本周的主題是作用域閉包,今天是第7天。 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進階計...

    simpleapples 評論0 收藏0
  • 【進階1-1期】理解JavaScript 中的執行上下文和執行棧

    摘要:首次運行代碼時,會創建一個全局執行上下文并到當前的執行棧中。執行上下文的創建執行上下文分兩個階段創建創建階段執行階段創建階段確定的值,也被稱為。 (關注福利,關注本公眾號回復[資料]領取優質前端視頻,包括Vue、React、Node源碼和實戰、面試指導) 本周正式開始前端進階的第一期,本周的主題是調用堆棧,,今天是第一天 本計劃一共28期,每期重點攻克一個面試重難點,如果你還不了解本進...

    import. 評論0 收藏0

發表評論

0條評論

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