亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

JavaScript基礎(chǔ)系列---閉包及其應(yīng)用

leoperfect / 3146人閱讀

摘要:所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。所以本文中將以維基百科中的定義為準(zhǔn)即在計(jì)算機(jī)科學(xué)中,閉包,又稱詞法閉包或函數(shù)閉包,是引用了自由變量的函數(shù)。

閉包(closure)是JavaScript中一個(gè)“神秘”的概念,許多人都對(duì)它難以理解,我也一直處于似懂非懂的狀態(tài),前幾天深入了解了一下執(zhí)行環(huán)境以及作用域鏈,可戳查看詳情,而閉包與作用域及作用域鏈的關(guān)系密不可分,所以就再深入去理解了一番。

詞法作用域Lexical Scope

首先我們來理解一下作用域的概念:

通常來說,一段程序代碼中所用到的標(biāo)識(shí)符并不總是有效/可用的,而限定這個(gè)標(biāo)識(shí)符的可用性的代碼范圍就是這個(gè)標(biāo)識(shí)符的作用域

作用域有詞法作用域與動(dòng)態(tài)作用域之分,詞法作用域也可稱為靜態(tài)作用域,這樣與動(dòng)態(tài)作用域看起來更對(duì)應(yīng)。

詞法作用域在詞法分析階段就確定了作用域,之后不會(huì)再改變;也就是說詞法作用域是由你把代碼寫在哪里來決定的,與之后的運(yùn)行情況無(wú)關(guān)

動(dòng)態(tài)作用域在運(yùn)行時(shí)根據(jù)程序的流程信息來動(dòng)態(tài)確定作用域;也就是說動(dòng)態(tài)作用域與運(yùn)行情況有關(guān)

大部分編程語(yǔ)言都是基于詞法作用域,其中包括JavaScript

下面我們使用代碼來說明兩者的區(qū)別(此處僅僅使用JavaScript來說明兩種情況,實(shí)際上JavaScript只基于詞法作用域)

var cc = 6;

function foo() {
  console.log(cc); // 會(huì)輸出6還是66?
}

function bar() {
  var cc = 66;
  foo();
}

bar();

如果是詞法作用域:會(huì)輸出6,詞法作用域在寫代碼時(shí)就靜態(tài)確定了,也就是定義foo函數(shù)的時(shí)候就確定了,foo函數(shù)的內(nèi)部要訪問變量cc,由于foo的內(nèi)部作用域中沒有cc變量,所以會(huì)根據(jù)作用域鏈訪問到全局中的cc變量;這與在何處調(diào)用foo函數(shù)無(wú)關(guān)。

如果是動(dòng)態(tài)作用域:會(huì)輸出66,動(dòng)態(tài)作用域要根據(jù)代碼的運(yùn)行情況來確定,它關(guān)心foo函數(shù)在何處被調(diào)用,而不關(guān)心它定義在哪里;foo函數(shù)的內(nèi)部要訪問變量cc,而foo的內(nèi)部作用域中沒有cc變量時(shí),會(huì)順著調(diào)用棧在調(diào)用 foo() 的地方查找變量cc,此處是在bar函數(shù)中調(diào)用的,所以引擎會(huì)在bar的內(nèi)部作用域中查找cc變量,這個(gè)cc變量的值為66

詞法作用域鏈Lexical Scope Chain
var cc = 1;

function foo() {
  var dd = 2;
  console.log(cc);//1
  console.log(dd);//2
}

foo();
console.log(dd); //ReferenceError: dd is not defined

上面這一段代碼中,有全局變量cc以及局部變量dd,在foo函數(shù)內(nèi)部可以直接訪問全局變量cc,而在foo函數(shù)外部無(wú)法讀取foo函數(shù)內(nèi)的局部變量dd。
這種結(jié)果的產(chǎn)生源于JavaScript的作用域鏈,也正是因?yàn)檫@個(gè)作用域鏈才有了生成閉包的可能。
作用域鏈這一部分在另一篇文章中有詳細(xì)介紹,可戳JavaScript基礎(chǔ)系列---執(zhí)行環(huán)境與作用域鏈,看完可以幫助更好的理解下文

什么是閉包?

關(guān)于閉包沒有一個(gè)官方的定義,不同的書籍解讀可能有些不同

在《JavaScript權(quán)威指南》中:

是指函數(shù)變量可以被隱藏于作用域鏈之內(nèi),因此看起來是函數(shù)將變量“包裹”了起來

在《JavaScript高級(jí)程序設(shè)計(jì)》中:

閉包是指有權(quán)訪問另一個(gè)函數(shù)作用域中的變量的函數(shù)

在《你不知道的JavaScript--上卷》中:

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

在維基百科的定義:

在計(jì)算機(jī)科學(xué)中,閉包(Closure),又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。所以,有另一種說法認(rèn)為閉包是由函數(shù)和與其相關(guān)的引用環(huán)境組合而成的實(shí)體。閉包在運(yùn)行時(shí)可以有多個(gè)實(shí)例,不同的引用環(huán)境和相同的函數(shù)組合可以產(chǎn)生不同的實(shí)例。

其中自由變量指:

在函數(shù)中使用的,但既不是函數(shù)參數(shù)也不是函數(shù)的局部變量的變量

一開始我也一直糾結(jié)于閉包的定義,想確切的知道閉包是什么,但是由于沒有官方的定義,難以確定。所以本文中將以維基百科中的定義為準(zhǔn)即:

在計(jì)算機(jī)科學(xué)中,閉包(Closure),又稱詞法閉包(Lexical Closure)或函數(shù)閉包(function closures),是引用了自由變量的函數(shù)。這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外。
閉包的創(chuàng)建

根據(jù)閉包的定義我們可以看出,閉包的產(chǎn)生條件是函數(shù)以及該函數(shù)引用了自由變量,二者缺一不可。

這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外這一描述是閉包的特性,使用閉包后能觀察到的一種現(xiàn)象,而不是閉包產(chǎn)生的條件。所以之前看到有些人說,需要將一個(gè)函數(shù)的內(nèi)部函數(shù)返回才能算閉包的言論我覺得應(yīng)該是不正確的,這應(yīng)該是在使用閉包。

常說的閉包會(huì)導(dǎo)致性能問題,也是因?yàn)?strong>這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外這一閉包特性,按理來說,在函數(shù) 執(zhí)行后,函數(shù)的整個(gè)內(nèi)部作用域通常都會(huì)被銷毀,因?yàn)槲覀冎酪嬗欣?br>圾回收器用來釋放不再使用的內(nèi)存空間,但是閉包可以阻止這件事的發(fā)生,從而可能導(dǎo)致內(nèi)存中保存大量的變量,從而消耗大量?jī)?nèi)存產(chǎn)生網(wǎng)頁(yè)性能問題。(注意是可以,可能而非一定)

下面我們直接來看幾個(gè)栗子:
1.如果考慮全局對(duì)象,那么引用了全局變量的函數(shù)可以看做創(chuàng)建了閉包,因?yàn)槿肿兞肯鄬?duì)于該函數(shù)來說是自由變量

var a = 1;
function fa() {
    console.log(a);
}
fa();

此處,函數(shù)fa引用了自由變量a,fa創(chuàng)建了閉包

2.更常見的是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)

function outer(){
    var b = 2;
    function inner(){
        console.log(b);
    }
    inner();
}
outer();

此處,函數(shù)inner引用了自由變量b,inner創(chuàng)建了閉包。
根據(jù)JavaScript基礎(chǔ)系列---執(zhí)行環(huán)境與作用域鏈中的描述我們可以知道,調(diào)用outer()后,會(huì)進(jìn)入Function Execution Context outer的創(chuàng)建階段:

創(chuàng)建作用域鏈,outer函數(shù)的[[Scopes]]屬性被加入其中

創(chuàng)建outer函數(shù)的活動(dòng)對(duì)象AO(作為該Function Execution Context的變量對(duì)象VO),并將創(chuàng)建的這個(gè)活動(dòng)對(duì)象AO加到作用域鏈的最前端

確定this的值

此時(shí)Function Execution Context outer可表示為:

outerEC = {
    scopeChain: {
        pointer to outerEC.VO,
        outer.[[Scopes]]
    },
    VO: {
        arguments: {
            length: 0
        },
        b: 2,
        inner: pointer to function inner(),
    },
    this: { ... }
}

接著進(jìn)入Function Execution Context outer的執(zhí)行階段:

當(dāng)遇到inner函數(shù)定義語(yǔ)句,進(jìn)入inner函數(shù)的定義階段,inner[[Scopes]]屬性被確定

inner.[[Scopes]] = {
    pointer to outerEC.VO,
    pointer to globalEC.VO
}

遇到inner()調(diào)用語(yǔ)句,進(jìn)入inner函數(shù)調(diào)用階段,此時(shí)進(jìn)入Function Execution Context inner的創(chuàng)建階段:

創(chuàng)建作用域鏈,inner函數(shù)的[[Scopes]]屬性被加入其中

創(chuàng)建inner函數(shù)的活動(dòng)對(duì)象AO(作為該Function Execution Context的變量對(duì)象VO),并將創(chuàng)建的這個(gè)活動(dòng)對(duì)象AO加到作用域鏈的最前端

確定this的值

此時(shí)Function Execution Context inner可表示為:

innerEC = {
    scopeChain: {
        pointer to innerEC.VO,
        inner.[[Scopes]]
    },
    VO: {
        arguments: {
            length: 0
        },
    },
    this: { ... }
}

接著進(jìn)入Function Execution Context inner的執(zhí)行階段:遇到打印語(yǔ)句console.log(b);,通過inner.[[Scopes]]訪問到變量b=2

至此,函數(shù)inner執(zhí)行完畢,Function Execution Context inner的作用域鏈及變量對(duì)象被銷毀

然后函數(shù)outer也執(zhí)行完畢,Function Execution Context outer的作用域鏈及變量對(duì)象被銷毀。

這種情況下,函數(shù)執(zhí)行完畢后該銷毀的都被銷毀了,沒有占用內(nèi)存,所以這種情況下閉包是不會(huì)對(duì)性能有占用內(nèi)存方面的影響的。

3.最常被討論的閉包

栗子1

function fa(){
    var n = 666;
    function fb(){
        console.log(n);
    }
    return fb;
}
var getN = fa();
getN();

此處,函數(shù)fb引用了自由變量nfb創(chuàng)建了閉包,并且fb被傳遞到了創(chuàng)造它的環(huán)境以外(所在的詞法作用域以外)。

這段代碼的執(zhí)行情況與上面類似,鑒于篇幅就不一一展開詳細(xì)描述了,大家可以自己推一遍;現(xiàn)在主要描述一下不同之處,在fa函數(shù)的最后,fa函數(shù)將它的內(nèi)部函數(shù)fb返回了,按理說返回之后fa函數(shù)就執(zhí)行完畢了,其作用域鏈和活動(dòng)對(duì)象應(yīng)該被銷毀,但是閉包fb阻止了這件事的發(fā)生:

函數(shù)fb定義之后其[[Scopes]]屬性被確定,這個(gè)屬性至此之后一直保持不變,直至函數(shù)fb被銷毀,可以表示為

fb.[[Scopes]] = {
    pointer to fa.VO,
    pointer to globalEC.VO
}

函數(shù)fa執(zhí)行完畢后,將其返回值--fb函數(shù)賦給了全局變量getN,這樣一來由于getN是全局變量,而全局變量是在Global Execution Context中的,需要等到應(yīng)用程序退出后 —— 如關(guān)閉網(wǎng)頁(yè)或?yàn)g覽器 —— 才會(huì)被銷毀,那么也就意味著fb函數(shù)也要到這時(shí)才會(huì)被銷毀

fb函數(shù)的[[Scopes]]屬性中引用了fa函數(shù)的變量(活動(dòng))對(duì)象,意味著fa函數(shù)的變量(活動(dòng))對(duì)象可能隨時(shí)還需要用到,這樣一來fa函數(shù)執(zhí)行完畢之后,只有Function Execution Context fa的作用域鏈會(huì)被銷毀,而變量(活動(dòng))對(duì)象仍然會(huì)在內(nèi)存中

這樣遇到getN()語(yǔ)句時(shí),實(shí)際上就是調(diào)用fb函數(shù),于是順著fb的作用域鏈找到變量n并打印出來

這里我們分析一下,變量n是閉包fb引用的自由變量,創(chuàng)造這個(gè)n這個(gè)自由變量的是函數(shù)fa,此時(shí)fa執(zhí)行完畢之后,自由變量n仍然可以訪問到(仍然存在),并且在fa函數(shù)外也能訪問到(離開fa之后)。這一點(diǎn)也就正對(duì)應(yīng)于這個(gè)被引用的自由變量將和這個(gè)函數(shù)一同存在,即使已經(jīng)離開了創(chuàng)造它的環(huán)境也不例外

除了將內(nèi)部函數(shù)return這種方式之外,還有其他方式可以使用閉包,這些方式的共同之處是:將內(nèi)部函數(shù)傳遞到創(chuàng)造它的環(huán)境以外(所在的詞法作用域以外),之后無(wú)論在何處執(zhí)行這個(gè)函數(shù)就都會(huì)使用閉包。

栗子2

function foo() {
    var a = 2;
    function baz() {
        console.log( a ); // 2
    }
    bar( baz );
}
function bar(fn) {
    fn();
}
foo();

這個(gè)栗子中,是通過函數(shù)傳參來將內(nèi)部函數(shù)baz傳遞到它所在的詞法作用域以外的

栗子3

var fn;
function foo() {
    var a = 2;
    function baz() {
        console.log( a );
    }
    fn = baz; // 將baz 賦給全局變量
}
foo();
fn(); // 2

這個(gè)栗子中,是通過賦值給全局變量fn來將內(nèi)部函數(shù)baz傳遞到它所在的詞法作用域以外的。

在栗子1和栗子3這種情況下呢,閉包使得它自己的變量對(duì)象以及包含它的函數(shù)的變量對(duì)象都存在于內(nèi)存中,如果濫用就很有可能導(dǎo)致性能問題。所以在不需要閉包后,最好主動(dòng)解除對(duì)閉包的引用,告訴垃圾回收機(jī)制將其清除,比如在上面這些例子中進(jìn)行getN = null;fn = null的操作。

4.經(jīng)常用但可能并沒有意識(shí)到它就是閉包的閉包

栗子1

function wait(msg) {
    setTimeout( function timer() {
        console.log( msg );
    }, 1000 );
}
wait( "Hello, closure!" );

上面的代碼其實(shí)可以理解為下面這樣:

function wait(msg) {
    function timer(){
        console.log( msg );
    }
    setTimeout( timer, 1000 );
}
wait( "Hello, closure!" );

內(nèi)部函數(shù)timer引用了自由變量msg,timer創(chuàng)建了閉包,然后將timer傳遞給setTimeout(..),也就是將內(nèi)部函數(shù)timer傳遞到了所在的詞法作用域以外。

當(dāng)wait(..) 執(zhí)行1000 毫秒后,wait的變量對(duì)象并不會(huì)消失,timer函數(shù)可以訪問變量msg,只有當(dāng)setTimeout(..)執(zhí)行完畢后,wait的變量對(duì)象才會(huì)被銷毀。

栗子2

function bindName(name, selector) {
    $( selector ).click( function showName() {
        console.log( "This name is: " + name );
    } );
}
bindName( "Closure", "#closure" );

上面的代碼其實(shí)可以理解為下面這樣:

function bindName(name, selector) {
    function showName(){
        console.log( "This name is: " + name );
    }
    $( selector ).click( showName );
}
bindName( "Closure", "#closure" );

內(nèi)部函數(shù)showName引用了自由變量name,showName創(chuàng)建了閉包,然后將showName傳遞給click事件作為回調(diào)函數(shù),也就是將內(nèi)部函數(shù)showName傳遞到了所在的詞法作用域以外。
當(dāng)bindName(..)執(zhí)行之后,bindName的變量對(duì)象并不會(huì)消失,每當(dāng)這個(gè)click事件觸發(fā)的時(shí)候showName函數(shù)可以訪問變量name。

5.同一個(gè)調(diào)用函數(shù)創(chuàng)建的閉包共享引用的自由變量

function change() {
    var num = 10;
        return{
        up:function() {
            num++;
            console.log(num);
        },
        down:function(){
            num--;
            console.log(num);
        }
    }
}
var opt = change();
opt.up();//11
opt.up();//12
opt.down();//11
opt.down();//10

opt.upopt.down共享變量num的引用,它們操作的是同一個(gè)變量num,因?yàn)檎{(diào)用一次change只會(huì)創(chuàng)建并進(jìn)入一個(gè)Function Execution Context change,通過閉包留在內(nèi)存中的變量對(duì)象只有一個(gè)。

6.不同調(diào)用函數(shù)創(chuàng)建的閉包互不影響

function change() {
   var num = 10;
       return{
       up:function() {
           num++;
           console.log(num);
       },
       down:function(){
           num--;
           console.log(num);
       }
   }
}
var opt1 = change();
var opt2 = change();
opt1.up();//11
opt1.up();//12
opt2.down();//9
opt2.down();//8

change函數(shù)被調(diào)用了兩次,分別賦值給opt1opt2,此時(shí)opt1.up,opt2.up以及opt1.down,opt2.down是互不影響的,因?yàn)槊空{(diào)用一次就會(huì)創(chuàng)建并進(jìn)入一個(gè)新的Function Execution Context change,也就會(huì)有新的變量對(duì)象,所以不同調(diào)用函數(shù)通過閉包留在內(nèi)存中的變量對(duì)象是獨(dú)立的,互不影響的。

7.關(guān)于上面提到的兩點(diǎn),有一個(gè)談到閉包就被拿出來的例子:

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

上述例子乍一看會(huì)覺得輸出的結(jié)果是:每隔1s分別打印出1,2,3,4,5;然而實(shí)際上的結(jié)果是:每隔1s分別打印出6,6,6,6,6。

那么是為什么會(huì)這樣呢?下面就來解析一下(ES6之前沒有let命令,不存在真正的塊級(jí)作用域):

變量i此處為全局變量,我們考慮全局變量,那么傳遞給setTimeout(...)的這個(gè)匿名函數(shù)創(chuàng)建了閉包,因?yàn)樗昧俗兞?b>i;雖然循環(huán)中的五個(gè)函數(shù)是在各次迭代中分別定義的,但是它們引用的是全局變量i,這個(gè)i只有一個(gè),所以它們引用的是同一個(gè)變量(如果在此處將全局對(duì)象想象成一個(gè)僅調(diào)用了一次的函數(shù)的返回值,那么這個(gè)現(xiàn)象便可以對(duì)應(yīng)于 ———— 同一個(gè)調(diào)用函數(shù)創(chuàng)建的閉包共享引用的自由變量)

setTimeout()的回調(diào)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行,即使每個(gè)迭代中執(zhí)行的是setTimeout(.., 0),而循環(huán)結(jié)束時(shí)全局變量i的值已經(jīng)變成6了,所以最后輸出的結(jié)果是每隔1s分別打印出6,6,6,6,6。

要解決上面這個(gè)問題,最簡(jiǎn)單的方式當(dāng)然是ES6中喜人的let命令了,僅需將var改為let即可,for 循環(huán)頭部的let 聲明會(huì)有一個(gè)特殊的行為。這個(gè)行為指出變量在循環(huán)過程中不止被聲明一次,每次迭代都會(huì)聲明。隨后的每個(gè)迭代都會(huì)使用上一個(gè)迭代結(jié)束時(shí)的值來初始化這個(gè)變量。

拋開喜人的ES6,又該怎么解決呢,既然上面的問題是由于共享同一個(gè)變量而導(dǎo)致的,那么我想辦法讓它不共享,而是每個(gè)函數(shù)引用一個(gè)不同的變量不就好了。上面提到了 ———— 不同調(diào)用函數(shù)創(chuàng)建的閉包互不影響,我們就要利用這個(gè)來解決這個(gè)問題:

for(var i=1;i<6;i++){
   waitShow(i);
}

function waitShow(j){
    setTimeout(function(){
        console.log(j);
    },j*1000);
}

我們將循環(huán)內(nèi)的代碼改成了一個(gè)函數(shù)調(diào)用語(yǔ)句waitShow(i),而waitShow函數(shù)的內(nèi)容就是之前循環(huán)體內(nèi)的內(nèi)容;waitShow內(nèi)部傳遞給setTimeout(...)的這個(gè)匿名函數(shù)仍然創(chuàng)建了閉包,只不過這次引用的是waitShow的參數(shù)j。

現(xiàn)在每迭代一次,便會(huì)調(diào)用waitShow一次,而我們從上文中已經(jīng)知道不同調(diào)用函數(shù)創(chuàng)建的閉包互不影響,所以就可以解決問題了!當(dāng)然,這還不是你常見的樣子,現(xiàn)在我們稍稍改動(dòng)一下,就變成非常常見的IIFE形式了:

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

balabala說了這么多,其實(shí)我們平常寫代碼的時(shí)候經(jīng)常無(wú)意識(shí)的就創(chuàng)建了閉包,但是創(chuàng)建了我們不一定會(huì)去使用閉包,而閉包的“威力”需要通過使用才能看得到。

閉包的應(yīng)用

閉包到底有什么用呢?我覺得總結(jié)成一句話就是:

“凍結(jié)”閉包的包含函數(shù)調(diào)用時(shí)的變量對(duì)象(使其以當(dāng)前值留在內(nèi)存中),并只有通過該閉包才能“解凍”(訪問/操作留在內(nèi)存中的變量對(duì)象)

粗看可能不是很能理解,下面我們結(jié)合具體的應(yīng)用場(chǎng)景來理解:

恩。。。首先我們來看一個(gè)老朋友,剛剛見過面的老朋友

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

在這個(gè)栗子中,每個(gè)IIFE自調(diào)用時(shí),其內(nèi)部創(chuàng)建的閉包將其當(dāng)時(shí)的變量對(duì)象“凍結(jié)”了,并且通過將這個(gè)閉包作為setTimeout的參數(shù)傳遞到IIFE作用域以外;所以第一次循環(huán)“凍結(jié)”的j的值是1,第二次循環(huán)“凍結(jié)”的j的值是2......當(dāng)循環(huán)結(jié)束后,延遲時(shí)間到了后,setTimeout的回調(diào)執(zhí)行(即使用閉包),“解凍”了之前“凍結(jié)”的變量j,然后打印出來。

既然提到setTimeout,那再來看看另外一個(gè)應(yīng)用,我們知道在標(biāo)準(zhǔn)的setTimeout是可以向延遲函數(shù)傳遞額外的參數(shù)的,形式是這樣:setTimeout(function[, delay, param1, param2, ...]),,一旦定時(shí)器到期,它們會(huì)作為參數(shù)傳遞給function。但是萬(wàn)惡的IE搞事情,在IE9及其之前的版本中是不支持傳遞額外參數(shù)的。那有時(shí)候我們確實(shí)有需要傳參數(shù),怎么辦呢。通常的解決方法有下面這些:

function fullName( givenName ){
    let familyName = "Swift";
    console.log("The fullName is: " + givenName + " " + familyName);
}
setTimeout(fullName,1000,"Taylor Alison");

使用一個(gè)匿名函數(shù)包裹

setTimeout(function(){
    fullName("Taylor Alison");
},1000);

使用bindES5引入)

setTimeout(fullName.bind(undefined,"Taylor Alison"),1000);

polyfill

使用閉包

function fullName( givenName ){
    let familyName = "Swift";
    return function(){
        console.log("The fullName is: " + givenName + " " + familyName);
    }
    
}
let showFullName = fullName("Taylor Alison");
setTimeout(showFullName,1000);

fullName內(nèi)的匿名函數(shù)創(chuàng)建了閉包,并作為返回值返回,調(diào)用fullName()后返回值賦給變量showFullName,此時(shí)fullName的變量對(duì)象被“凍結(jié)”,只能通過showFullName才能“解凍”,定時(shí)器到期后,showFullName被調(diào)用,通過之前被“凍結(jié)”的變量對(duì)象訪問到givenNamefamilyName。

待續(xù)(有時(shí)間補(bǔ)上)

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

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

相關(guān)文章

  • JS 閉包(closure)

    摘要:對(duì)數(shù)組函數(shù)而言,相當(dāng)于產(chǎn)生了個(gè)閉包。關(guān)于對(duì)象在閉包中使用對(duì)象也會(huì)導(dǎo)致一些問題。不過,匿名函數(shù)的執(zhí)行環(huán)境具有全局性,因此其對(duì)象通常指向。由于聲明函數(shù)時(shí)與聲明函數(shù)時(shí)的值是不同的,因此閉包與閉包貌似將會(huì)表示各自不同的值。 這幾天看到閉包一章,從工具書到各路大神博客,都各自有著不同的理解,以下我將選擇性的抄(咳咳,當(dāng)然還是會(huì)附上自己理解的)一些大神們對(duì)閉包的原理及其使用文章,當(dāng)作是自己初步理解...

    nihao 評(píng)論0 收藏0
  • 【重溫基礎(chǔ)】22.內(nèi)存管理

    摘要:內(nèi)存泄露內(nèi)存泄露概念在計(jì)算機(jī)科學(xué)中,內(nèi)存泄漏指由于疏忽或錯(cuò)誤造成程序未能釋放已經(jīng)不再使用的內(nèi)存。判斷內(nèi)存泄漏,以字段為準(zhǔn)。 本文是 重溫基礎(chǔ) 系列文章的第二十二篇。 今日感受:優(yōu)化學(xué)習(xí)方法。 系列目錄: 【復(fù)習(xí)資料】ES6/ES7/ES8/ES9資料整理(個(gè)人整理) 【重溫基礎(chǔ)】1-14篇 【重溫基礎(chǔ)】15.JS對(duì)象介紹 【重溫基礎(chǔ)】16.JSON對(duì)象介紹 【重溫基礎(chǔ)】1...

    Pandaaa 評(píng)論0 收藏0
  • 前端基礎(chǔ)

    摘要:談起閉包,它可是兩個(gè)核心技術(shù)之一異步基于打造前端持續(xù)集成開發(fā)環(huán)境本文將以一個(gè)標(biāo)準(zhǔn)的項(xiàng)目為例,完全拋棄傳統(tǒng)的前端項(xiàng)目開發(fā)部署方式,基于容器技術(shù)打造一個(gè)精簡(jiǎn)的前端持續(xù)集成的開發(fā)環(huán)境。 這一次,徹底弄懂 JavaScript 執(zhí)行機(jī)制 本文的目的就是要保證你徹底弄懂javascript的執(zhí)行機(jī)制,如果讀完本文還不懂,可以揍我。 不論你是javascript新手還是老鳥,不論是面試求職,還是日...

    graf 評(píng)論0 收藏0
  • JS筆記

    摘要:從最開始的到封裝后的都在試圖解決異步編程過程中的問題。為了讓編程更美好,我們就需要引入來降低異步編程的復(fù)雜性。異步編程入門的全稱是前端經(jīng)典面試題從輸入到頁(yè)面加載發(fā)生了什么這是一篇開發(fā)的科普類文章,涉及到優(yōu)化等多個(gè)方面。 TypeScript 入門教程 從 JavaScript 程序員的角度總結(jié)思考,循序漸進(jìn)的理解 TypeScript。 網(wǎng)絡(luò)基礎(chǔ)知識(shí)之 HTTP 協(xié)議 詳細(xì)介紹 HTT...

    rottengeek 評(píng)論0 收藏0
  • JavaScript 工作原理之三-內(nèi)存管理及如何處理 4 類常見的內(nèi)存泄漏問題(譯)

    摘要:這是因?yàn)槲覀冊(cè)L問了數(shù)組中不存在的數(shù)組元素它超過了最后一個(gè)實(shí)際分配到內(nèi)存的數(shù)組元素字節(jié),并且有可能會(huì)讀取或者覆寫的位。包含個(gè)元素的新數(shù)組由和數(shù)組元素所組成中的內(nèi)存使用中使用分配的內(nèi)存主要指的是內(nèi)存讀寫。 原文請(qǐng)查閱這里,本文有進(jìn)行刪減,文后增了些經(jīng)驗(yàn)總結(jié)。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 這是 JavaScript 工作原理的第三章。 我們將會(huì)討論日常使用中另一個(gè)被開發(fā)...

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

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

0條評(píng)論

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