欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

js學(xué)習(xí)之----深入理解閉包

 更新時(shí)間:2016年11月21日 10:46:57   作者:_wind  
本篇文章主要介紹了js的閉包,閉包算是js里面比較不容易理解的點(diǎn),現(xiàn)在整理出來分享給大家,有需要的可以了解一下。

閉包算是js里面比較不容易理解的點(diǎn),尤其是對(duì)于沒有編程基礎(chǔ)的人來說。

其實(shí)閉包要注意的就那么幾條,如果你都明白了那么征服它并不是什么難事兒。下面就讓我們來談一談閉包的一些基本原理。

 閉包的概念

一個(gè)閉包就是一個(gè)函數(shù)和被創(chuàng)建的函數(shù)中的作用域?qū)ο蟮慕M合。(作用域?qū)ο笙旅鏁?huì)說)

通俗一點(diǎn)的就是 “ 只要一個(gè)函數(shù)中嵌套了一個(gè)或多個(gè)函數(shù),那么我們就可以稱它們構(gòu)成了閉包。 ”

類似這樣:

function A() {
 var i = 5;
 return function() {
  console.log('i = '+i);
 }
}

var a = A();
a(); // i = 5

閉包的原理

1、外部函數(shù)的局部變量若會(huì)被閉包函數(shù)調(diào)用就不會(huì)在外部函數(shù)執(zhí)行完畢之后立即被回收。

我們知道,不管什么語言,操作系統(tǒng)都會(huì)存在一個(gè)垃圾回收機(jī)制,將多余分配的空間回收掉以便減小內(nèi)存。而一個(gè)函數(shù)的生命周期的是從調(diào)用它開始的,在函數(shù)調(diào)用完畢的時(shí)候函數(shù)內(nèi)部的局部變量等都會(huì)被回收機(jī)制回收。

我們拿上述例子來說,當(dāng)我們的外部函數(shù)A調(diào)用完畢時(shí),A中的局部變量i按理說就會(huì)被操作系統(tǒng)回收而不存在,但是當(dāng)我們用了閉包結(jié)果就不是那樣了,i并不會(huì)被回收。試想,如果i被回收了那么返回的函數(shù)里面豈不是就是打印undefined了?

i為什么沒有被回收?

在javascript執(zhí)行一個(gè)函數(shù)的時(shí)候都會(huì)創(chuàng)建一個(gè)作用域?qū)ο?,將函?shù)中的局部變量(函數(shù)的形參也是局部變量)保存進(jìn)去,伴隨著那些傳入函數(shù)的變量一起被初始化。

所以當(dāng)調(diào)用A的時(shí)候就創(chuàng)建了一個(gè)作用域?qū)ο?,我們姑且稱之為Aa,那么這個(gè)Aa應(yīng)該是這樣的: Aa { i: 5; };  在A函數(shù)返回一個(gè)函數(shù)之后,A執(zhí)行完畢。Aa對(duì)象本應(yīng)該被回收,但是由于返回的函數(shù)使用了Aa的屬性i,所以返回的函數(shù)保存了一個(gè)指向Aa的引用,所以Aa不會(huì)被回收。

所以理解作用域?qū)ο?,就能理解為什么函?shù)的局部變量在遇到閉包的時(shí)候不會(huì)在函數(shù)調(diào)用完畢時(shí)立即被回收了。

再來個(gè)例子:

function A(age) {
 var name = 'wind';
 var sayHello = function() {
  console.log('hello, '+name+', you are '+age+' years old!');
 };
 return sayHello;
}
var wind = A(20);
wind(); // hello, wind, you are 20 years old!

你能說出的它的作用域?qū)ο骔w是什么嗎?

Ww{ age: 20; name: 'wind'; };

2、每調(diào)用一次外部函數(shù)就產(chǎn)生一個(gè)新的閉包,以前的閉包依舊存在且互不影響。

3、同一個(gè)閉包會(huì)保留上一次的狀態(tài),當(dāng)它被再次調(diào)用時(shí)會(huì)在上一次的基礎(chǔ)上進(jìn)行。

每調(diào)用一次外部函數(shù)產(chǎn)生的作用域?qū)ο蠖疾灰粯?,你可以這樣想,上面的例子,你每次傳入的參數(shù)age不一樣,所以就每次生成的對(duì)象不一樣。

每調(diào)用一次外部函數(shù)那么就會(huì)生成一個(gè)新的作用域?qū)ο蟆?/p>

function A() {
 var num = 42;
 return function() { console.log(num++); }
}
var a = A();
a(); // 42
a(); // 43

var b = A(); // 重新調(diào)用A(),形成新閉包
b(); // 42   

這個(gè)代碼讓我們發(fā)現(xiàn)了兩個(gè)事情,一、當(dāng)我們連續(xù)調(diào)用兩次a();,num會(huì)在原基礎(chǔ)上自加。說明同一個(gè)閉包會(huì)保留上一次的狀態(tài),當(dāng)它被再次調(diào)用時(shí)會(huì)在上一次的基礎(chǔ)上進(jìn)行。 二、我們的b();的結(jié)果為42,說明它是一個(gè)新的閉包,并且不受其他閉包的影響。

我們可以這樣想,就好比我們吹肥皂泡一樣,我每次吹一下(調(diào)用外部函數(shù)),就會(huì)產(chǎn)生一個(gè)新的肥皂泡(閉包),多個(gè)肥皂泡可以同時(shí)存在且兩個(gè)肥皂泡之間不會(huì)相互影響。

4、在外部函數(shù)中存在的多個(gè)函數(shù) “ 同生共死 ”

以下三個(gè)函數(shù)被同時(shí)聲明并且都可以對(duì)作用域?qū)ο蟮膶傩裕ň植孔兞浚┻M(jìn)行訪問與操作。

var fun1, fun2, fun3;
function A() {
 var num = 42;
 fun1 = function() { console.log(num); }
 fun2 = function() { num++; }
 fun3 = function() { num--; } 
}

A();
fun1();  // 42
fun2(); 
fun2(); 
fun1();  // 44
fun3(); 
fun1();  //43

var old = fun1;

A(); 
fun1();  // 42
old();  // 43  上一個(gè)閉包的fun1()

由于函數(shù)不能有多個(gè)返回值,所以我用了全局變量。我們?cè)俅慰梢钥闯鲈谖覀兊诙握{(diào)用A()時(shí)產(chǎn)生了一個(gè)新的閉包。

當(dāng)閉包遇到循環(huán)變量

當(dāng)我們說到閉包就不得不說當(dāng)閉包遇到循環(huán)變量這一種情況,看如下代碼:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    var item = 'item' + i;
    result.push( function() {console.log(item + ' ' + arr[i])} );
  }
  return result;
}

var fnlist = buildArr([1,2,3]);
fnlist[0](); // item2 undefined
fnlist[1](); // item2 undefined
fnlist[2](); // item2 undefined

怎么會(huì)這樣呢?我們預(yù)想的三個(gè)輸出應(yīng)該是 item0 1,  item1 2,  item2 3。為什么結(jié)果卻是返回的result數(shù)組里面存儲(chǔ)了三個(gè) item2 undefined ?

原來當(dāng)閉包遇到循環(huán)變量時(shí)都是循環(huán)結(jié)束之后統(tǒng)一保存變量值,拿我們上面的例子來說,i是循環(huán)變量,當(dāng)循環(huán)全部結(jié)束的時(shí)候i正好是i++之后的3,而arr[3]是沒有值的,所以為undefined,有人會(huì)疑惑:為什么item的值是item2,難道不應(yīng)該是item3嗎?注意,在最后一次循環(huán)的時(shí)候也就是i = 2的時(shí)候,item的值為item2,當(dāng)i++,i = 3循環(huán)條件不滿足循環(huán)結(jié)束,此時(shí)的item的值已經(jīng)定下來了,所以此時(shí)的arr[i]為arr[3],而item為item2。這樣能理解嗎?如果我們將代碼改成這樣那就說得通了:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) { 
    result.push( function() {console.log('item' + i + ' ' + arr[i])} );
  }
  return result;
}

var fnlist = buildArr([1,2,3]);
fnlist[1](); // item3 undefined

那么問題來了,如何改正呢?且看代碼:

function buildArr(arr) {
  var result = [];
  for (var i = 0; i < arr.length; i++) {
    result.push( (function(n) {
      return function() {
       var item = 'item' + n;
       console.log(item + ' ' + arr[n]);
      }
    })(i));
  }
  return result;
}

var fnlist = buildArr([1,2,3]);
fnlist[0](); // item0 1
fnlist[1](); // item1 2
fnlist[2](); // item2 3

我們可以用一個(gè)自執(zhí)行函數(shù)將i綁定,這樣i的每一個(gè)狀態(tài)都會(huì)被存儲(chǔ),答案就和我們預(yù)期的一樣了。

所以以后在使用閉包的時(shí)候遇到循環(huán)變量我們要習(xí)慣性的想到用自執(zhí)行函數(shù)來綁定它。

以上就是我對(duì)閉包的理解,如果有什么意見或建議希望我們能在評(píng)論區(qū)多多交流。感謝,共勉。

相關(guān)文章

  • JS中數(shù)據(jù)結(jié)構(gòu)之棧

    JS中數(shù)據(jù)結(jié)構(gòu)之棧

    棧是一種遵從后進(jìn)先出(LIFO)原則的有序集合。新添加的或待刪除的元素都保存在棧末尾,稱作棧頂,另一端稱作棧底。在棧里,新元素都靠近棧頂,舊元素就接近棧底。
    2019-01-01
  • 簡(jiǎn)介JavaScript中Boolean.toSource()方法的使用

    簡(jiǎn)介JavaScript中Boolean.toSource()方法的使用

    這篇文章主要介紹了簡(jiǎn)介JavaScript中Boolean.toSource()方法的使用,是JS入門學(xué)習(xí)中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-06-06
  • Dojo Javascript 編程規(guī)范 規(guī)范自己的JavaScript書寫

    Dojo Javascript 編程規(guī)范 規(guī)范自己的JavaScript書寫

    良好的JavaScript書寫習(xí)慣的優(yōu)點(diǎn)不言而喻,今天彬Go向大家推薦Dojo Javascript 編程規(guī)范,相當(dāng)不錯(cuò)的 Javascript 編程風(fēng)格規(guī)范,建議大家可以借鑒一下此規(guī)范編寫 Javascript。感謝i.feelinglucky的翻譯
    2014-10-10
  • javascript 學(xué)習(xí)筆記(六)瀏覽器類型及版本信息檢測(cè)代碼

    javascript 學(xué)習(xí)筆記(六)瀏覽器類型及版本信息檢測(cè)代碼

    由于各瀏覽器對(duì)css以及js支持的差異性,我們?cè)谧銮岸碎_發(fā)時(shí),經(jīng)常需要先檢測(cè)瀏覽器的類型及版本,然后會(huì)對(duì)各自的差異性來寫代碼!
    2011-04-04
  • TypeScript中的函數(shù)和類你了解嗎

    TypeScript中的函數(shù)和類你了解嗎

    這篇文章主要為大家詳細(xì)介紹了TypeScript中的函數(shù)和類,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-03-03
  • js資料prototype 屬性

    js資料prototype 屬性

    js資料prototype 屬性...
    2007-03-03
  • JavaScript中的數(shù)據(jù)類型介紹

    JavaScript中的數(shù)據(jù)類型介紹

    這篇文章介紹了JavaScript中的數(shù)據(jù)類型,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • Javascript基礎(chǔ)教程之a(chǎn)rgument 詳解

    Javascript基礎(chǔ)教程之a(chǎn)rgument 詳解

    這篇文章主要介紹了Javascript基礎(chǔ)教程之a(chǎn)rgument 詳解的相關(guān)資料,需要的朋友可以參考下
    2015-01-01
  • javascript教程之不完整的繼承(js原型鏈)

    javascript教程之不完整的繼承(js原型鏈)

    Javascript的繼承和標(biāo)準(zhǔn)的oop繼承有很大的區(qū)別,Javascript的繼承是采用原型鏈的技術(shù),下面使用示例學(xué)習(xí)一下JS的繼承
    2014-01-01
  • JavaScript數(shù)據(jù)類型詳解

    JavaScript數(shù)據(jù)類型詳解

    這篇文章主要介紹了JavaScript數(shù)據(jù)類型詳解,本文詳細(xì)講解了JavaScript中有5種基本數(shù)據(jù)類型:Undefined、Null、Boolean、Number和String,需要的朋友可以參考下
    2015-04-04

最新評(píng)論