js 閉包

  前言:常常看到不少面試題裏有閉包的問題,包括一些程序裏邊也看到過閉包的寫法,一直不知道閉包究竟是個什麼東西?有什麼樣的做用?爲何要使用閉包?接下來我就把這幾天在網上看到的各位大神們寫的關於閉包的文章的一種總結吧(鑑於本身以爲看起來有點懂的文章,說實話看了好多文章,仍是似懂非懂,汗~ v ~)javascript

1、什麼是閉包php

  1>.維基百科的定義:在計算機科學中,閉包(英文:Closure),又稱詞法閉包或者函數閉包,是引用了自由變量的函數。html

    重點關鍵詞/語句:詞法閉包、函數閉包、自由變量。java

  2>.阮一峯老師的關於js閉包的概念:閉包就是可以讀取其餘函數內部的變量(其餘函數的內部變量也就是我們說的局部變量);因爲在Javascript語言中,只有函數內部的子函數才能讀取局部變量,所以能夠把閉包簡單理解成"定義在一個函數內部的函數"。因此,在本質上,閉包就是將函數內部和函數外部鏈接起來的一座橋樑。c++

    重點關鍵詞/語句:局部變量、函數內部的函數、函數內部與外部鏈接起來git

  3>.ECMAScript 中閉包的定義:詞法表示包括不被計算的變量的函數,換句話說,函數可使用函數以外定義的變量github

    重點關鍵詞/語句:函數以外定義的變量(這裏說的函數以外的變量包含了全局變量、函數對應的父級變量(多是全局變量,也多是局部變量))面試

  其餘的我就不一一列舉了,大體我看的就這麼幾種...segmentfault

2、閉包的用途(做用)閉包

  我相信這也是不少人最關心的問題,閉包這個東西到底有什麼用?用它有什麼好處?用在什麼地方?接下來就來看看

  1>.阮一峯老師的關於閉包用途的描述:閉包能夠用在許多地方。它的最大用處有兩個,一個是前面提到的能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中

  2>.網上其餘描述1:閉包的最主要使用場景就是設計私有的方法和變量(閉包在作框架封裝的時候體現的更明顯,有些方法和屬性只是運算邏輯過程當中的使用,所以就可以使用閉包的方式,只提供方法和屬性的獲取)

  分析1: 

function A(num)
{
    var count = 0;
    for(i = 0; i < num; i++)
    {
        count += i;
    }

    console.log(count); // res - 3
}

A(3);
console.log(i); // res - 3

   上邊的代碼中,咱們常常這麼使用,那麼這個時候會形成的一個問題就是這個i變量,一旦這個函數執行了,那麼這個i變量就會變成一個全局的變量(重點:在javascript中,函數內部聲明變量使用var聲明的變量是局部變量,做用域只在該函數內,而不使用var聲明的變量,在函數執行以後就會升級成爲全局變量,注意了,升級爲全局變量的前提是該函數執行了,該函數不執行的話,你輸出該變量會提示未定義Undefined),這樣的話就會形成對全局環境的一個污染,爲何會這樣呢?緣由在於javascript中沒有塊級做用域,不像其餘的語言,i的做用域和生命週期只在for循環中,一旦循環結束,i也會被自動銷燬掉;接下來我使用閉包的方式改寫一下上邊的代碼:

function A(num) {
    //核心代碼
    (function(){
        for(var i = 0; i<num; i++) {
            console.log(i); // 0 1 2
        }
    })();
    //核心代碼結束
    console.log(i)//underfined
}

A(3);
console.log(i); //underfined

  改代碼我使用了一個匿名函數把循環放到匿名函數內,這其實就是一個閉包了,那麼能夠看到i變量在匿名函數執行完畢後輸出,會提示underfined,在A函數外邊全局環境中輸出也是提示underfined,在這裏使用閉包的方式就避免了過多的全局變量和函數,形成全局環境的混亂(要是多人合做開發的話,那狀況可想而知......)。

  3>.閉包能夠模仿塊級做用域:在好比c++、java這些語言中有塊級做用域(i只在for循環內有效,一旦for循環結束i就會被自動銷燬掉),而javascript中沒有,因此閉包能夠很好的實現出塊級做用域的做用,能夠保證全局環境的乾淨,不會出現變量衝突等一些問題;

 

  分析2(驗證"閉包用途的描述:能夠讀取函數內部的變量、變量的值始終保持在內存中"):

    其實這個讀取函數內部的變量上邊的代碼中已經驗證了,函數內部的子函數能夠讀取父級函數的局部變量,父級的局部變量相對於子函數就是自由變量  

function B()
{
    var count = 0;
    return function () {
        console.log(++count);
    }
}

var m = B();
m(); // 1
m(); // 2
m(); // 3

  上邊的代碼我是直接返回出了一個匿名函數,那麼打眼一看有沒有發現什麼呢?沒錯,那就是變量的值始終保持在了m這個對象中(本身語言的描述,不標準勿怪),執行一次加一,匿名函數引用了count變量,因此B執行後count不會被釋放,利用這一點,咱們能夠把比較重要或者計算耗費很大的值存在count中,只須要第一次計算賦值後,就能夠經過m函數引用count的值,沒必要重複計算,同時也不容易被修改(由於是局部變量,B函數外部是沒法作修改的,作到了將變量持久的保存在內存中(本人本身語言描述,勿怪......))

  總結:閉包能夠將變量長期的保存在內存中,作到持久化

  分析3(驗證:閉包就是將函數內部和函數外部鏈接起來的一座橋樑,也就是說函數外部操做函數內部的變量-局部變量):

    首先咱們都知道javascript中是沒有私有變量這一說的,不像php代碼可使用private來聲明私有變量,那麼在javascript中,哪一種變量纔是具備私有性質的變量呢?那就是我們常說的局部變量,why?其實你們仔細想一下就明白了,在函數內部聲明的變量是局部變量,做用域只在該函數內部,在執行該函數的時候,函數內部的變量會初始化被建立並賦值,一旦函數執行完畢,那麼該函數內部聲明的變量也會被銷燬,而在函數外部是不能訪問到函數內部的變量的,因此這個函數內部的變量相對於整個全局環境來講就是一個私有變量,是該函數私有的變量(做用域),那麼怎麼能作到函數外部能操做"別人私有的東西"呢?這就是接下來咱們要驗證的閉包的另外一個用途:

function Person()
{
    var defaultName = 'closure';
    i = 2; //i在Person函數執行後至關於全局變量
    this.getName = function () {
        return defaultName;
    };

    this.setName = function (value) {
        defaultName = value;
    };
}

var result = new Person(); // 這時result就是這個Person函數的實例對象
console.log(result.getName()); //closure
result.setName('zgw2014');
console.log(result.getName()); //zgw2014
console.log(result.defaultName); //undefined(局部變量在外部是不能直接訪問的,經過函數返回函數自己對象訪問也不行)
console.log(i); //2

  上邊的代碼就實現了閉包成爲了將函數內部和函數外部鏈接起來的一個橋樑,這樣就作到了在函數外部訪問和操做函數內部的私人變量(局部變量)的目的

  總結:閉包能夠實現操做函數內部的私有變量,讓函數內外進行鏈接

  暫時就寫這麼多,之後再更新.......

引用借鑑:

  https://segmentfault.com/a/1190000008681174

  http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html

  https://github.com/lin-xin/blog/issues/8

  https://github.com/mqyqingfeng/Blog/issues/9

       https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Closures

很是感謝貢獻這麼多好文章的做者們......

相關文章
相關標籤/搜索