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

資訊專欄INFORMATION COLUMN

你不知道的JavaScript:閉包

weknow619 / 2380人閱讀

摘要:回憶我一年前,雖然使用過很多,但卻完全不理解閉包是什么。就算你,也會在循環(huán)完成時,輸出次當然,不要以為主要的原因是延遲函數(shù)會在循環(huán)結(jié)束時才執(zhí)行,不然我為什么會在閉包這一節(jié)用使用這個例子,哈哈。

前言

在了解閉包的概念時,我希望你能夠有JavaScript詞法作用域的知識,因為它會讓你更容易讀懂這篇文章。

感觸

對于那些使用過JavaScript但卻完全不理解閉包概念的人來說,理解閉包可以看做是某種意義上的重生,但是你需要付出大量的努力和犧牲才能理解這個概念。
回憶我一年前,雖然使用過很多JavaScript,但卻完全不理解閉包是什么。當我了解到模塊模式的時候,我才激動地發(fā)現(xiàn)了原來這就是閉包?

JavaScript中閉包無處不在,你只需要能夠識別并擁抱它。
開始

直接上定義
當函數(shù)可以記住并訪問所在的作用域時,就產(chǎn)生了閉包。即函數(shù)是在當前詞法作用域之外執(zhí)行

function foo () {
    const a = 2
    function bar () {
        console.log(a)
    }
    return bar
}
const baz = foo()
baz() // 2  ---  媽媽呀!這就是閉包?太簡單了吧!

函數(shù)foo()使用它的內(nèi)部方法 bar()作為返回值,而bar()內(nèi)部有著對foo()作用域的引用(即a),在執(zhí)行foo()過后,內(nèi)部函數(shù)bar()賦值給baz,調(diào)用baz()顯然可以執(zhí)行bar()。
可以看到bar()在自身作用域之外執(zhí)行了,通常在foo()執(zhí)行過后,我們會覺得foo()會被JS引擎的垃圾回收機制銷毀,實際上并不會,因為baz有著對bar()的引用,而bar()內(nèi)部有著foo()作用域的引用,因此foo()并不會被銷毀,以供bar()在任何時間被引用,因此bar()記住了并訪問了自身所在的foo()作用域。
當然,這兒還有另外一個例子:

function foo () {
    const a = 2
    function baz () {
        console.log(a)
    }
    bar(baz)
}
function bar (fn) {
    fn() // 這就是閉包
}

本例中,baz()在foo()之外調(diào)用,并且baz()自身有著涵蓋foo()作用域的引用,因此baz()可以記住foo()的作用域,保證其不會被垃圾回收機制銷毀

現(xiàn)在我懂了

上一節(jié)的代碼過于死板,我們來看看更實用的代碼。

function wait (message) {
    setTimeout(function timer () {
        console.log(message)
    }, 1000)
}
wait("hello")

很明顯,內(nèi)部函數(shù)timer()持有對wait()的閉包
或者在jQuery中

function setupBot (name, selector) {
    $(selector).click(function activator () {
        console.log(name)
    })
}
setupBot ("hello", "#bot")

可以看到,閉包在你寫的代碼中無處不在,特別是回調(diào)函數(shù),全是閉包

循環(huán)與閉包

給一個經(jīng)典的案例

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

你可能會天真的以為它會輸出:1,2,3,4,5?
事實上,它會以每秒一次的頻率輸出5次6
為什么?
因為延遲函數(shù)會在循環(huán)結(jié)束時才執(zhí)行。就算你setTimeout(...,0),也會在循環(huán)完成時,輸出5次6
當然,不要以為主要的原因是延遲函數(shù)會在循環(huán)結(jié)束時才執(zhí)行,不然我為什么會在閉包這一節(jié)用使用這個例子,哈哈。
那么真正導致這個與預(yù)期不符的是閉包
首先內(nèi)部函數(shù)timer()有著涵蓋for循環(huán)的閉包,這5次調(diào)用timer()都是封閉在同一個作用域中,他們共享同一個i,只有一個i
那么我們?nèi)绾巫屗凑瘴覀兊念A(yù)期,輸出1,2,3,4,5呢?
當然是讓每個timer(),都有一個屬于自己的i,這里的解決方案有很多:

IIFE立即執(zhí)行函數(shù)可以形成一個塊作用域,我們只需要把每次迭代的i,保存在timer()的塊作用域中,通過這個保存的值打印出來就ok了

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

ES6中的const或者let,它們都可以構(gòu)造一個塊級作用域(PS:const 定義常量,無法被修改

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

我們可以用let稍微改進一下(為什么在for循環(huán)中使用let,不用const,上面已經(jīng)說得很清楚了

for(let i = 1 ; i <= 5; i ++) {
    setTimeout(function timer () {
        console.log(i)
    }, i * 1000)
}

不知道你怎么想,反正塊級作用域閉包的使用,讓我成為了一只快樂的JavaScript程序員

模塊

這是閉包運用得最廣的地方了吧
看看下面的代碼

  function Module(){
    const something = "Do A"
    const another = "Do B"
    function doA(){
      console.log(something)
    }

    function doB(){
      console.log(another)
    }
    return {
      doA,
      doB
    }
  }
  const foo = Module()
  foo.doA()
  foo.doB()

這種模式,在JavaScript中被稱為模塊,其中包含的閉包,相信大家一眼就看出來了吧。
Module()中的 doA() 與 doB() 都包含了對Module()的閉包
那么模塊模式需要具備的條件是:

必須有外部的封閉函數(shù),且至少被調(diào)用一次(每次調(diào)用都會產(chǎn)生一個新的模塊)

封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),形成閉包,并且可以修改和訪問私有狀態(tài)。

由于調(diào)用一次就會產(chǎn)生一個模塊,那么是否有單例模式呢?

  const foo = (function Module(another){
    const something = "Do A"
    function doA(){
      console.log(something)
    }

    function doB(another){
      console.log(another)
    }
    return {
      doA,
      doB
    }
  })()
  foo.doA()
  foo.doB("Do B")

通過IIFE,立即調(diào)用這個模塊,只暴露foo,那么這個模塊只有foo這一個實例。

現(xiàn)在的模塊機制
// bar.js
function hello(who) {
    return `hello ${who}`
}
export hello
// foo.js
// 僅導入hello()
import hello from "bar"

const name = "jack"
function awesome () {
    console.log(hello(name))
}
export awesome
// baz.js
// 導入完整模塊
module foo from "foo"
module bar from "bar"

console.log(bar.hello("john"))
foo.awesome()

這里模塊文件中的內(nèi)容同樣被當做好像包含在作用域中的閉包一樣處理

小結(jié)

閉包就好像是JavaScript中,充滿神奇色彩的一部分,但是當我們揭開她的面紗,才發(fā)現(xiàn)她竟然這么美,她一直陪在你身邊,但是你卻一直逃避她,這次我不想你再錯過她了。

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

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/95120.html

相關(guān)文章

  • 重讀你不知道JS (上) 第一節(jié)五章

    摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關(guān),即使本身并不會真的使用閉包。而上面的創(chuàng)建一個閉包,本質(zhì)上這是將一個塊轉(zhuǎn)換成一個可以被關(guān)閉的作用域。結(jié)合塊級作用域與閉包模塊這個模式在中被稱為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術(shù)的語言,即使是經(jīng)驗豐富的 Jav...

    worldligang 評論0 收藏0
  • [JS]《你不知道Javascript·上》——詞法作用域和閉包

    摘要:吐槽一下,閉包這個詞的翻譯真是有很大的誤解性啊要說閉包,要先說下詞法作用域。閉包兩個作用通過閉包,在外部環(huán)境訪問內(nèi)部環(huán)境的變量。閉包使得函數(shù)可以繼續(xù)訪問定義時的詞法作用域。 閉包是真的讓人頭暈啊,看了很久還是覺得很模糊。只能把目前自己的一些理解先寫下來,這其中必定包含著一些錯誤,待日后有更深刻的理解時再作更改。 吐槽一下,閉包這個詞的翻譯真是有很大的誤解性啊…… 要說閉包,要先說下詞法...

    guqiu 評論0 收藏0
  • 你不知道javascript》筆記_作用域與閉包

    摘要:建筑的頂層代表全局作用域。實際的塊級作用域遠不止如此塊級作用域函數(shù)作用域早期盛行的立即執(zhí)行函數(shù)就是為了形成塊級作用域,不污染全局。這便是閉包的特點吧經(jīng)典面試題下面的代碼輸出內(nèi)容答案個如何處理能夠輸出閉包方式方式下一篇你不知道的筆記 下一篇:《你不知道的javascript》筆記_this 寫在前面 這一系列的筆記是在《javascript高級程序設(shè)計》讀書筆記系列的升華版本,旨在將零碎...

    galaxy_robot 評論0 收藏0
  • 你不知道 JavaScript 筆記——作用域和閉包

    摘要:理解作用域在引擎看來是兩個完全不同的聲明。在循環(huán)中使用閉包閉包是函數(shù)和聲明該函數(shù)的詞法環(huán)境的組合。回到我們上面說的在自己定義的作用域以外的地方執(zhí)行,這里聲明的是全局變量,使用全局變量不構(gòu)成閉包。 第一章:作用域是什么 程序中變量存儲在哪里,需要是怎么找到它,這就需要設(shè)計一套存儲以及能方便的找到它的規(guī)則,這個規(guī)則就是作用域 編譯原理 JavaScript 是一門編譯語言,它與傳統(tǒng)編譯語言...

    BearyChat 評論0 收藏0
  • 十分鐘快速了解《你不知道 JavaScript》(上卷)

    摘要:最近剛剛看完了你不知道的上卷,對有了更進一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對象原型。附錄詞法這一章并沒有說明機制,只是介紹了中的箭頭函數(shù)引入的行為詞法。第章混合對象類類理論類的機制類的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對 JavaScript 有了更進一步的了解。 《你不知道的 JavaScript》上卷由兩部...

    趙春朋 評論0 收藏0

發(fā)表評論

0條評論

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