成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

閉包理解

niceforbear / 3477人閱讀

摘要:什么是閉包紅寶書上給出的定義是閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),看到另外一個(gè)理解是函數(shù)和函數(shù)內(nèi)部能訪問到的變量或者環(huán)境的總合,就是一個(gè)閉包。閉包用于創(chuàng)建單例所謂單例,就是只有一個(gè)實(shí)例的對(duì)象。它使用立即執(zhí)行函數(shù)和閉包來(lái)達(dá)到目的。

面試必問題目,但總覺得理解得不深入,索性寫一篇文章慢慢梳理吧。

什么是閉包

紅寶書上給出的定義是:閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù),看到另外一個(gè)理解是:函數(shù)和函數(shù)內(nèi)部能訪問到的變量(或者環(huán)境)的總合,就是一個(gè)閉包。創(chuàng)建一個(gè)閉包最常見的方式就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)。下面寫一個(gè)例子:

function f1() {
  var a = 1;
  function closure() {
    console.log(++a);
  } 
  return closure;
}

上面例子中,f1 內(nèi)部的匿名函數(shù)以及它能夠訪問到的外部函數(shù)的變量 a 合在一起,就形成了一個(gè)閉包。使用 return 將閉包返回的目的是讓它可以被外部訪問。下面看看它怎么使用:

var f2 = f1();   // 執(zhí)行外部函數(shù),返回閉包
f2();     // 2
f2();     // 3
f2();     // 4

第一句執(zhí)行函數(shù) f1() 后,閉包被返回并賦值給了一個(gè)全局變量 f2,以后每次調(diào)用 f2(),變量 a 的值就會(huì)加 1。通常函數(shù)執(zhí)行完畢后,其作用域鏈和活動(dòng)對(duì)象都會(huì)被銷毀,為什么這里 a 并沒有被銷毀并且每次執(zhí)行 f2() 還會(huì)被遞增?原因是閉包有權(quán)訪問外部函數(shù)的變量,進(jìn)一步說,閉包的作用域鏈會(huì)引用外部函數(shù)的活動(dòng)對(duì)象,所以 f2() 在執(zhí)行時(shí),其作用域鏈實(shí)際上是:

自身的活動(dòng)對(duì)象;

f1() 的活動(dòng)對(duì)象;

全局變量對(duì)象。

所以 f1() 執(zhí)行完后,其執(zhí)行環(huán)境的作用域鏈會(huì)被銷毀,但活動(dòng)對(duì)象仍然會(huì)留在內(nèi)存中,因?yàn)殚]包作用域鏈在引用這個(gè)活動(dòng)對(duì)象(說白了就是閉包還需要使用外層函數(shù)的變量,不允許它們被銷毀),直到閉包被銷毀后,f1() 的活動(dòng)對(duì)象才會(huì)被銷毀。

上面例子中,是將返回的閉包賦值給了一個(gè)全局變量 f2var f2 = f1();,f2 是不會(huì)被銷毀的,每次執(zhí)行完 f2(),閉包的作用域鏈不會(huì)被銷毀,所以就會(huì)出現(xiàn)每次執(zhí)行 f2(),a 遞增。

但是換一種閉包的調(diào)用方式,情況會(huì)不同:

f1()();   // 2
f1()();   // 2

因?yàn)闆]有把閉包賦值給一個(gè)全局變量,閉包執(zhí)行完后,其執(zhí)行域鏈與活動(dòng)對(duì)象都銷毀了。

閉包的作用 創(chuàng)建用于訪問私有變量的公有方法

其實(shí)構(gòu)造函數(shù)中定義的實(shí)例方法,就是閉包:

function Person(){
  var name = "Leon";
  function sayHi() {
    alert("Hi!");
  }
  this.publicMethod = function() {
    alert(name);
    return sayHi();
  }
}

構(gòu)造函數(shù) Person 中定義實(shí)例方法 publicMethod() 就是一個(gè)閉包,它可以訪問外部函數(shù)的變量 name 和 函數(shù) sayHi(),為什么要這么做呢?因?yàn)槲覀兿朐跇?gòu)造函數(shù)中定義一些私有變量,讓外部不能直接訪問,只能通過定義好的公有方法訪問,從而達(dá)到保護(hù)變量,收斂外部權(quán)限的目的。

而在普通函數(shù)中,把閉包 return 出去供外部使用,其實(shí)目的也就是:讓函數(shù)內(nèi)部的變量始終保持在內(nèi)存中,同時(shí)保護(hù)這些變量,讓它們不能被直接訪問。

function person(){
  var name = "Leon";
  function sayHi() {
    alert("Hi!");
  }
  function publicMethod() {
    alert(name);
    return sayHi();
  }
  return publicMethod;
}
閉包用于創(chuàng)建單例

所謂單例,就是只有一個(gè)實(shí)例的對(duì)象。單例模式的好處在于:

保證一個(gè)類只有一個(gè)實(shí)例,避免了一個(gè)在全局范圍內(nèi)使用的實(shí)例頻繁創(chuàng)建與銷毀。

比如網(wǎng)頁(yè)中的彈窗,點(diǎn)擊 a 按鈕彈出,點(diǎn)擊 b 按鈕隱藏,如果彈窗每一次彈出都需要新建一個(gè)對(duì)象,將會(huì)造成性能的浪費(fèi),更好的辦法就是只實(shí)例化一個(gè)對(duì)象,一直使用。

劃分了命名空間,避免了與全局命名空間的沖突。

比如在一個(gè)單例中可以定義很多方法,通過單例.方法來(lái)使用,避免了在全局環(huán)境中定義函數(shù),造成函數(shù)名沖突。

下面逐步介紹下單例的創(chuàng)建方式,后兩種方式將用到閉包。

1. 對(duì)象字面量創(chuàng)建單例
var singleton = {
  attr1: 1,
  attr2: 2,
  method: function () {
    return this.attr1 + this.attr2;
  }
}
var s1 = singleton;
var s2 = singleton;
console.log(s1 == s2)  // true

上面用字面量形式創(chuàng)建了一個(gè)單例,可以看到 s1s2 是等同的。這種方式的問題在于外部可以直接訪問單例的內(nèi)部變量并加以修改,如果想讓單例擁有私有變量,就需要使用模塊模式,模塊模式就是用了閉包。

2. 模塊模式

JS 中的模塊模式的作用是:為單例添加私有變量和公有方法。它使用立即執(zhí)行函數(shù)和閉包來(lái)達(dá)到目的。

var singleton = (function(){
  // 創(chuàng)建私有變量
  var privateNum = 1;
  // 創(chuàng)建私有函數(shù)
  function privateFunc(){
    console.log(++privateNum);
  }
  // 返回一個(gè)對(duì)象包含公有方法
  return {
      publicMethod: function(){
        console.log(privateNum)
        return privateFunc()
      }
  };
})();

singleton.publicMethod();
// 1
// 2 

這里首先定義了一個(gè)立即執(zhí)行函數(shù),它返回一個(gè)對(duì)象,該對(duì)象中有一個(gè)閉包 publicMethod(), 它可以訪問外部函數(shù)的私有變量。從而這個(gè)被返回的對(duì)象就成為了單例的公共接口,外部可以通過它的公有方法訪問私有變量而無(wú)權(quán)直接修改。總結(jié)一下就是兩點(diǎn):

立即執(zhí)行函數(shù)可以創(chuàng)建一個(gè)塊級(jí)作用域, 避免在全局環(huán)境中添加變量。

閉包可以訪問外層函數(shù)中的變量。

3. 構(gòu)造函數(shù)+閉包

上面提到的對(duì)象字面是用來(lái)創(chuàng)建單例的方法之一,既然單例只能被實(shí)例化一次,不難想到,在使用構(gòu)造函數(shù)新建實(shí)例時(shí),先判斷實(shí)例是否已被新建,未被新建則新建實(shí)例,否則直接返回已被新建的實(shí)例。

var Singleton = function(name){
  this.name = name;
};

// 獲取實(shí)例對(duì)象
var getInstance = (function() {
  var instance = null;
  return function(name) {
      if(!instance) {
          instance = new Singleton(name);
      }
      return instance;
  }
})();

var a = getInstance("1");
console.log(a);  // {name: "1"}
var b = getInstance("2");
console.log(b);  // {name: "1"}

這里將構(gòu)造函數(shù)和實(shí)例化過程進(jìn)行了分離, getInstance()中存在一個(gè)閉包,它可以訪問到外部變量 instance,第一次 instance = null,則通過 new Singleton(name) 新建實(shí)例,并將這個(gè)實(shí)例保存在instance 中,之后再想新建實(shí)例,因?yàn)殚]包訪問到的instance已經(jīng)有值了,就會(huì)直接返回之前實(shí)例化的對(duì)象。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/108459.html

相關(guān)文章

  • 多層級(jí)理解閉包

    摘要:第二梯隊(duì)理解有了第一梯隊(duì)的認(rèn)識(shí),我們慢慢修正大腦中對(duì)閉包的認(rèn)識(shí)。理解這句話就可以很好的與閉包這兩個(gè)字關(guān)聯(lián)起來(lái)理解閉包這個(gè)概念了。總結(jié)第二梯隊(duì)理解閉包是一個(gè)有特定功能的函數(shù)。第四梯隊(duì)理解閉包通過訪問外部變量,一個(gè)閉包可以維持這些變量。 閉包 閉包的概念困惑了我很久,記得當(dāng)時(shí)我面試的時(shí)候最后一面有一個(gè)問題就是問題關(guān)于閉包的問題,然而到現(xiàn)在已經(jīng)完全不記得當(dāng)時(shí)的題目是啥了,但仍然能夠回憶起當(dāng)時(shí)...

    nemo 評(píng)論0 收藏0
  • 理解 JavaScript 閉包

    摘要:如何在初學(xué)就理解閉包你需要接著讀下去。這樣定義閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。小結(jié)閉包在中隨處可見。閉包是中的精華部分,理解它需要具備一定的作用域執(zhí)行棧的知識(shí)。 這是本系列的第 4 篇文章。 作為 JS 初學(xué)者,第一次接觸閉包的概念是因?yàn)閷懗隽祟愃葡旅娴拇a: for (var i = 0; i < helpText.length; i++) { var item = he...

    寵來(lái)也 評(píng)論0 收藏0
  • 談?wù)勎宜?em>理解的閉包,js、php、golang里的closure

    摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語(yǔ)言,讓我們來(lái)看一下語(yǔ)言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對(duì)閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語(yǔ)言,發(fā)現(xiàn)不光是js,php、...

    betacat 評(píng)論0 收藏0
  • 談?wù)勎宜?em>理解的閉包,js、php、golang里的closure

    摘要:當(dāng)初看這個(gè)解釋有點(diǎn)懵逼,理解成閉包就是函數(shù)中的函數(shù)了。里的閉包最近不滿足于只干前端的活,開始用起了。里的閉包最近在學(xué)習(xí)語(yǔ)言,讓我們來(lái)看一下語(yǔ)言里的閉包。在中,閉包特指將函數(shù)作為值返回的情況,被返回的函數(shù)引用了生成它的母函數(shù)中的變量。 本人開始接觸編程是從js開始的,當(dāng)時(shí)網(wǎng)上很多人說閉包是難點(diǎn),各種地方對(duì)閉包的解釋也是千奇百怪。如今開始接觸js以外的各種編程語(yǔ)言,發(fā)現(xiàn)不光是js,php、...

    zhoutao 評(píng)論0 收藏0
  • 簡(jiǎn)單理解JavaScript中的閉包

    摘要:閉包在我理解是一種比較抽象的東西。所以我寫了一篇博文來(lái)方便自己理解閉包。那么現(xiàn)在我們可以解釋一下閉包的第一個(gè)定義在計(jì)算機(jī)科學(xué)中,閉包是引用了自由變量的函數(shù)。循環(huán)中創(chuàng)建閉包在我們使用的關(guān)鍵字之前,閉包的一個(gè)常見問題就出現(xiàn)在循環(huán)中創(chuàng)建閉包。 零. 前言 從我開始接觸前端時(shí)就聽說過閉包,但是一直不理解閉包究竟是什么。上網(wǎng)看了各種博客,大家對(duì)閉包的說法不一。閉包在我理解是一種比較抽象的東西。所...

    sihai 評(píng)論0 收藏0
  • 理解Javascript的閉包

    摘要:但是閉包也不是什么復(fù)雜到不可理解的東西,簡(jiǎn)而言之,閉包就是閉包就是函數(shù)的局部變量集合,只是這些局部變量在函數(shù)返回后會(huì)繼續(xù)存在??上У氖?,并沒有提供相關(guān)的成員和方法來(lái)訪問閉包中的局部變量。 (收藏自 技術(shù)狂) 前言:還是一篇入門文章。Javascript中有幾個(gè)非常重要的語(yǔ)言特性——對(duì)象、原型繼承、閉包。其中閉包 對(duì)于那些使用傳統(tǒng)靜態(tài)語(yǔ)言C/C++的程序員來(lái)說是一個(gè)新的語(yǔ)言特性。本文將...

    dayday_up 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<