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

資訊專欄INFORMATION COLUMN

再談閉包-詞法作用域

Ku_Andrew / 2201人閱讀

摘要:權(quán)威指南第六版關(guān)于閉包的說(shuō)明采用詞法作用域,也就是說(shuō)函數(shù)的執(zhí)行依賴于變量的作用域,這個(gè)作用域是在函數(shù)定義時(shí)決定的,而不是函數(shù)調(diào)用時(shí)決定的。閉包這個(gè)術(shù)語(yǔ)的來(lái)源指函數(shù)變量可以被隱藏于作用域鏈之內(nèi),因此看起來(lái)是函數(shù)將變量包裹了起來(lái)。

最近打算換工作,所以參加了幾次面試(國(guó)內(nèi)比較知名的幾家互聯(lián)網(wǎng)公司)。在面試的過(guò)程中每當(dāng)被問(wèn)起閉包,我都會(huì)說(shuō)閉包是作用域的問(wèn)題?令人驚訝的是幾乎無(wú)一例外的當(dāng)我提到作用域時(shí)我都被打斷,并提醒我好好的找一本javascript的書籍看看。而當(dāng)我忍不住去問(wèn)面試官對(duì)于閉包你是怎么理解的?我得到的大多是回答都是通過(guò)返回一個(gè)函數(shù),然后通過(guò)這個(gè)函數(shù)來(lái)訪問(wèn)局部變量(私有變量),有的還會(huì)扯上聲明提前,this指向等。聽(tīng)到這些,心理默默滴血,沒(méi)錯(cuò),我只是菜鳥。

看到有這么多人不理解閉包,所以我不得不再次的提及,如果有誤,歡迎指正。

閉包只是為了實(shí)現(xiàn)詞法作用域而用到的一種數(shù)據(jù)結(jié)構(gòu)而已

先從阮一峰09年寫的一篇關(guān)于閉包的文章開始(原文地址)文中說(shuō)"可以把閉包理解為就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù),因?yàn)閖s中,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量,因此也可以把閉包定義在一個(gè)函數(shù)內(nèi)部的函數(shù)。所以閉包本質(zhì)就是將函數(shù)內(nèi)部和函數(shù)外部連接起來(lái)的一座橋梁"。

畢竟不是專業(yè)學(xué)習(xí)js的,也不是程序語(yǔ)言方面的專家,在這里就不去計(jì)較了,下文會(huì)給出更完整的閉包說(shuō)明。(PS:個(gè)人還是比較欣賞阮一峰寫的文章的,能將一些概念講得通俗易懂)

最后還留下了一個(gè)思考題

示例01:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());

示例02:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
  alert(object.getNameFunc()());

看完這道題,就希望大家將this和閉包分開,不要給自己找麻煩?

在開始說(shuō)閉包之前,需要理解好以下的概念:

詞法作用域(靜態(tài)作用域)

函數(shù)上下文

之前簡(jiǎn)單的提過(guò),詞法作用域簡(jiǎn)單的理解就是函數(shù)的上下文是在聲明是確定的,而不是在調(diào)用時(shí)確定的。這里不想對(duì)這兩個(gè)名詞作過(guò)多的解釋,我們知道js/ruby/python等主流的語(yǔ)言都是詞法作用域就好,因?yàn)榕c之相對(duì)的動(dòng)態(tài)作用域有許多的問(wèn)題,所以現(xiàn)在的語(yǔ)言基本都是詞法作用域的。

函數(shù)上下文就簡(jiǎn)單的理解為函數(shù)執(zhí)行的環(huán)境好了,在這個(gè)環(huán)境中保存了函數(shù)執(zhí)行所需的變量。

JavaScript權(quán)威指南第六版關(guān)于閉包的說(shuō)明

JavaScript采用詞法作用域,也就是說(shuō)函數(shù)的執(zhí)行依賴于變量的作用域,這個(gè)作用域是在函數(shù)定義時(shí)決定的,而不是函數(shù)調(diào)用時(shí)決定的。為了實(shí)現(xiàn)詞法作用域,JavaScript函數(shù)對(duì)象的內(nèi)部狀態(tài)不僅包含函數(shù)的代碼邏輯,還必須引用當(dāng)前的作用域鏈。函數(shù)對(duì)象可以通過(guò)作用域鏈相互關(guān)聯(lián)起來(lái),函數(shù)體內(nèi)部的變量都可以保存在函數(shù)作用域內(nèi),這種特性在計(jì)算機(jī)科學(xué)文獻(xiàn)中稱為"閉包"。

當(dāng)定義一個(gè)函數(shù)時(shí),它實(shí)際上保存了一個(gè)作用域鏈。當(dāng)調(diào)用這個(gè)函數(shù)時(shí),它創(chuàng)建

一個(gè)新的對(duì)象來(lái)存儲(chǔ)它的局部變量,并將這個(gè)對(duì)象添加到保存的作用域鏈上。

(閉包可以簡(jiǎn)單的理解為函數(shù)用來(lái)存儲(chǔ)它的局部變量的對(duì)象,這個(gè)對(duì)象我們來(lái)說(shuō)是不可見(jiàn)的,是js解釋器實(shí)現(xiàn)的過(guò)程中才會(huì)用到的。每一個(gè)函數(shù)都會(huì)有這樣的一個(gè)對(duì)象,作用域鏈則是這些對(duì)象之間的關(guān)系。)

"閉包"這個(gè)術(shù)語(yǔ)的來(lái)源:指函數(shù)變量可以被隱藏于作用域鏈之內(nèi),因此看起來(lái)是函數(shù)將變量"包裹"了起來(lái)。

看文字可能會(huì)比較繞,下面是書中的一個(gè)例子:

var scope = "global scope";            /*全局變量*/
function checkscope(){
    var scope = "local scope";        /*局部變量*/
    function f(){return scope;}
    return f();
}
checkscope();                        /*=>"local scope"*/
var scope = "global scope";            /*全局變量*/
function checkscope(){
    var scope = "local scope";        /*局部變量*/
    function f(){return scope;}
    return f;
}
checkscope()();                        /*=>"local scope"*/

checkscope最后的返回值都是一樣的,即"local scope"。

上面兩個(gè)例子的不同之處就是函數(shù)f執(zhí)行的地方不同,一個(gè)在checkscope這個(gè)作用域里調(diào)用的(每一個(gè)函數(shù)都是一個(gè)作用域),一個(gè)在全局作用域里調(diào)用的。回憶之前說(shuō)的,函數(shù)調(diào)用時(shí)的上下文或者說(shuō)作用域是在聲明時(shí)確定的,所以與調(diào)用的位置無(wú)關(guān),即f函數(shù)的調(diào)用位置雖然不同,調(diào)用的環(huán)境雖然不同,但最終的結(jié)果都是一樣的。

說(shuō)到這里,閉包就說(shuō)得差不多了,回過(guò)頭來(lái)看一下常規(guī)的對(duì)于閉包的理解:

通過(guò)返回函數(shù)的形式取得函數(shù)的局部變量。

這種說(shuō)法本身沒(méi)有錯(cuò),但它只是閉包的一種表現(xiàn)形式,

比如將上例進(jìn)行下更改:

var scope = "global scope";            /*全局變量*/
function checkscope(fn){
    var scope = "local scope";        /*局部變量*/
    function f(){return scope;}
    fn(f);
}
checkscope(function(func){
    var scope = "func scope";
    return func();
});                                    /*=>"local scope"*/

改成類似回調(diào)的執(zhí)行方式,結(jié)果還是一樣的,注意結(jié)果并不是func scope,但是并沒(méi)有返回f函數(shù)這一說(shuō),難道這就不是閉包了嗎?(當(dāng)然這里有點(diǎn)扣字眼)

說(shuō)說(shuō)this

想起最開始時(shí)的那個(gè)思考題了嗎?與閉包就沒(méi)什么關(guān)系(注:任何一個(gè)函數(shù)其實(shí)都用到了閉包,但我們暫且考慮兩層以及兩層以上的嵌套情況,未嵌套情況下因?yàn)槭褂玫亩际侨肿饔糜?,結(jié)果應(yīng)該是很直觀的)。this一般用來(lái)代表函數(shù)的調(diào)用對(duì)象,它和上下文對(duì)象并不是同一個(gè),上下文對(duì)象對(duì)我們來(lái)說(shuō)是不可見(jiàn)的,除了全局作用域。

示例01:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      return function(){
        return this.name;
      };
    }
  };
  alert(object.getNameFunc()());        /*The Window*/

示例02:

  var name = "The Window";
  var object = {
    name : "My Object",
    getNameFunc : function(){
      var that = this;
      return function(){
        return that.name;
      };
    }
  };
   var that = {name: "xiaofu"};            /*干擾項(xiàng)*/ 
  alert(object.getNameFunc()());        /*My Object*/

我們?cè)賮?lái)看一下題目,示例01輸出的是"The Window",示例02輸出的是"My Object"。

說(shuō)明:

示例01最終執(zhí)行的是 function(){return this.name},因?yàn)闆](méi)有顯示指明調(diào)用對(duì)象,所以其this執(zhí)行全局對(duì)象。

示例02先調(diào)用object.getNameFunc(),因?yàn)轱@示的指定了調(diào)用對(duì)象,所以內(nèi)部的this是object(注:這里說(shuō)的是this指向的問(wèn)題,還沒(méi)有說(shuō)閉包),接著執(zhí)行function (){return that.name},這個(gè)函數(shù)在getNameFunc這個(gè)函數(shù)作用域中聲明的,所以它調(diào)用的時(shí)候使用的是這個(gè)作用域,即得到var that = this;的這個(gè)that;而不是外面的that。

作用域鏈不等同于原型鏈

真不知道這兩個(gè)不相關(guān)的東西怎么會(huì)被等同起來(lái)看待,以后誰(shuí)告訴我它們是同一個(gè)東西,我就想問(wèn)了,ruby、python這種沒(méi)有原型概念的語(yǔ)言難道就沒(méi)有作用域鏈了嗎?

更有甚者將變量聲明提升和閉包混在一起,也是醉了。

總結(jié)

閉包:函數(shù)執(zhí)行時(shí)變量的獲取從聲明的作用域處去獲取(注意鏈?zhǔn)疥P(guān)系,當(dāng)前沒(méi)有就往父級(jí)找,知道全局作用域)

this:顯示指定調(diào)用者則this就指向誰(shuí),如未指定則為全局對(duì)象

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

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

相關(guān)文章

  • 先有蛋還是先有雞?JavaScript 作用閉包探析

    摘要:而閉包的神奇之處正是可以阻止事情的發(fā)生。拜所聲明的位置所賜,它擁有涵蓋內(nèi)部作用域的閉包,使得該作用域能夠一直存活,以供在之后任何時(shí)間進(jìn)行引用。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫閉包。 引子 先看一個(gè)問(wèn)題,下面兩個(gè)代碼片段會(huì)輸出什么? // Snippet 1 a = 2; var a; console.log(a); // Snippet 2 console.log(a); v...

    elisa.yang 評(píng)論0 收藏0
  • 還擔(dān)心面試官問(wèn)閉包?

    摘要:一言以蔽之,閉包,你就得掌握。當(dāng)函數(shù)記住并訪問(wèn)所在的詞法作用域,閉包就產(chǎn)生了。所以閉包才會(huì)得以實(shí)現(xiàn)。從技術(shù)上講,這就是閉包。執(zhí)行后,他的內(nèi)部作用域并不會(huì)消失,函數(shù)依然保持有作用域的閉包。 網(wǎng)上總結(jié)閉包的文章已經(jīng)爛大街了,不敢說(shuō)筆者這篇文章多么多么xxx,只是個(gè)人理解總結(jié)。各位看官瞅瞅就好,大神還希望多多指正。此篇文章總結(jié)與《JavaScript忍者秘籍》 《你不知道的JavaScri...

    tinyq 評(píng)論0 收藏0
  • [JS]《你不知道的Javascript·上》——詞法作用閉包

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

    guqiu 評(píng)論0 收藏0
  • 你應(yīng)該要知道的作用閉包

    摘要:寫在前面對(duì)于一個(gè)前端開發(fā)者,應(yīng)該沒(méi)有不知道作用域的。欺騙詞法作用域有兩個(gè)機(jī)制可以欺騙詞法作用域和。關(guān)于你不知道的的第一部分作用域和閉包已經(jīng)結(jié)束了,但是,更新不會(huì)就此止住未完待續(xù) 這是《你不知道的JavaScript》的第一部分。 本系列持續(xù)更新中,Github 地址請(qǐng)查閱這里。 寫在前面 對(duì)于一個(gè)前端開發(fā)者,應(yīng)該沒(méi)有不知道作用域的。它是一個(gè)既簡(jiǎn)單有復(fù)雜的概念,簡(jiǎn)單到每行代碼都有它的影子...

    JouyPub 評(píng)論0 收藏0
  • 閉包詳解一

    摘要:再看一段代碼這樣就清晰地展示了閉包的詞法作用域能訪問(wèn)的作用域?qū)?dāng)做一個(gè)值返回執(zhí)行后,將的引用賦值給執(zhí)行,輸出了變量我們知道通過(guò)引用的關(guān)系,就是函數(shù)本身。 在正式學(xué)習(xí)閉包之前,請(qǐng)各位同學(xué)一定要確保自己對(duì)詞法作用域已經(jīng)非常的熟悉了,如果對(duì)詞法作用域還不夠熟悉的話,可以先看: 深入理解閉包之前置知識(shí)---作用域與詞法作用域 前言 現(xiàn)在去面試前端開發(fā)的崗位,如果你的面試官也是個(gè)前端,并且不是太...

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

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

0條評(píng)論

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