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

資訊專欄INFORMATION COLUMN

JS進擊之路:閉包

tolerious / 2509人閱讀

摘要:常見問題說到閉包相關的問題,最典型的就是變量和指向這兩類問題。如果有錯誤或不嚴謹的地方,歡迎批評指正,如果喜歡,歡迎點贊。

引言

閉包這個詞對很多前端開發人員來說既熟悉又陌生,熟悉是因為很多人都用過閉包,但是用的時候不知道閉包,陌生是因為并不理解閉包,接下來這篇文章將會從多方面介紹閉包

定義

閉包是怎么定義的呢?當函數可以記住并訪問所在的詞法作用域時,就產生了閉包,即使函數在當前詞法作用域之外執行。來看一個具體例子:

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

函數bar的詞法作用域可以訪問foo的內部作用域,并且bar在被作為返回值賦值給baz執行時,bar函數在定義時的詞法作用域以外的地方被調用,依然可以訪問foo函數的內部作用域變量a,這就是閉包

分析

現在讓我們來看為什么閉包可以在定義的詞法作用域外記住并且訪問定義時的詞法作用域的變量,想要一探究竟,先來看一個簡單的例子來函數的執行過程:

function foo (a) {
  console.log(a)
}
foo (a)


上面是一個簡單的函數調用,以及在執行時的上下文環境,重點看執行時上下文環境,在創建foo函數時,會創建一個預先包含全局變量對象的作用域鏈,這個作用域鏈被保存在內部的[[Scope]]屬性中,當調用foo()函數時,會為函數創建一個執行環境,然后通過復制函數的[[Scope]屬性中的對象構建起執行環境的作用域鏈。此后,又有一個活動對象(包含this、arguments、a)被創建并被推入執行環境作用域鏈的前端,對于foo函數來說,其作用域鏈包含兩個變量對象,一個時全局的變量對象,一個是局部的活動變量對象,一般來說當函數執行完成后,局部的活動變量對象會被銷毀,只留全局的,但是閉包執行過程有所不同,來看具體例子:

function foo () {
  var a = 2
  function bar (b) {
    console.log(a + b)
  }
  return bar
}
var baz = foo()
baz(3) //5


接下來來分析下上面閉包的執行上下環境,在一個函數內部定義的函數會將包含函數的活動對象添加到它的作用域鏈中,因此,bar函數的作用域鏈中會包含foo函數的活動對象,在bar函數從foo中被返回后,它的作用域鏈條被初始化為全局變量和foo中活動對象,因此,bar函數可以訪問foo函數中定義的所有變量,同時foo函數在執行完畢后,其活動對象也不會被銷毀,因為bar函數的作用域鏈仍然在引用這個活動對象。

常見問題

說到閉包相關的問題,最典型的就是變量和this指向這兩類問題。

變量
function test () {
  var result = new Array()
  for (var i = 0; i < 6; i++) {
    result[i] = function () {
      return i
    }
  }
  return result
}


上面的代碼展示就是面試題里面經常會碰到,result的結果從上面截圖能看到,作用域中保存的i都是6,這是為什么呢?因為閉包保存的是函數中的活動對象,因此它們引用的都是同一個變量,并且是變量的最后一個值,因此都是6,那這個問題怎么解決呢?最常見的最簡單肯定是將var換成let,也可以像下面這樣:

function test () {
  var result = new Array()
  for (var i = 0; i < 6; i++) {
    result[i] = (function () {
      return i
    })()
  }
  return result
}

將閉包直接改成一個自執行函數,自執行函數本身是沒有變量作用域的,因此會使用外層函數的變量作用域,這樣也能達到我們想要的效果

this指向
var name = "window"
var obj = {
  name: "object",
  getName: function () {
    return function () {
      return this.name
    }
  }
}
console.log(obj.getName()())

上面這段js代碼的this.name的返回值是window,這是為什么呢?按照上面寫到的,此匿名函數在執行過程中,它的作用域會包含三部分:自身的活動對象、getName函數的活動對象和全局的變量對象,同時每個活動對象自動取得兩個特殊的變量:this和arguments,但是內部函數在查找this時是無法直接訪問外部函數的this變量,因此會沿著作用域鏈去查找全局變量中繼續查找,如果想要取外部函數中的this取值也很簡單,只需要向下面代碼這樣:

var name = "window"
var obj = {
  name: "object",
  getName: function () {
    var that = this
    return function () {
      return that.name
    }
  }
}
console.log(obj.getName()())

將this賦值給一個變量,內部函數是可以訪問外部函數變量的,這樣就解決了

總結

閉包是一個容易混淆不清的概念,這篇文章對閉包的定義、執行、常見問題做了簡單的介紹,希望通過這篇能對大家理解和使用閉包有所幫助。如果有錯誤或不嚴謹的地方,歡迎批評指正,如果喜歡,歡迎點贊。

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/109262.html

相關文章

  • 進擊的 JavaScript(五) 之 立即執行函數與閉包

    摘要:匿名函數是不能單獨寫的,所以就提不上立即執行了。六立即執行函數在閉包中的應用立即執行函數能配合閉包保存狀態。來看下上節內容中閉包的例子現在,我們來利用立即執行函數來簡化它第一個匿名函數執行完畢后,返回了第二個匿名函數。 前面的閉包中,提到與閉包相似的立即執行函數,感覺兩者還是比較容易弄混吧,嚴格來說(因為犀牛書和高程對閉包的定義不同),立即執行函數并不屬于閉包,它不滿足閉包的三個條件。...

    vincent_xyb 評論0 收藏0
  • 進擊JavaScript之(三)玩轉閉包

    摘要:為了更好的理解,在閱讀此文之前建議先閱讀上一篇進擊之詞法作用域與作用域鏈什么是閉包閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。在中函數構成閉包。 為了更好的理解,在閱讀此文之前建議先閱讀上一篇《進擊JavaScript之詞法作用域與作用域鏈》 1.什么是閉包 閉包的含義就是閉合,包起來,簡單的來說,就是一個具有封閉功能與包裹功能的結構。所謂的閉包就是...

    cyixlq 評論0 收藏0
  • JS進擊之路:作用域

    摘要:如果是,編譯器會忽略該聲明,繼續進行編譯否則它會要求作用域在當前作用域的集合中聲明一個新的變量接下來編譯器會為引擎生成運行時所需的代碼,這些代碼被用來處理這個賦值操作。引擎運行時會首先詢問作用域,在當前的作用域集合中是否存在一個叫做的變量。 引言 幾乎所有的編程語言都有作用域的概念,那作用域到底指的是什么呢?作用域就是編程語言在定義變量時,變量如何存儲、變量如何訪問的一套規則,不同的編...

    el09xccxy 評論0 收藏0
  • 進擊的 JavaScript(四) 之 閉包

    摘要:此時產生了閉包。導致,函數的活動對象沒有被銷毀。是不是跟你想的不一樣其實,這個例子重點就在函數上,這個函數的第一個參數接受一個函數作為回調函數,這個回調函數并不會立即執行,它會在當前代碼執行完,并在給定的時間后執行。 上一節說了執行上下文,這節咱們就乘勝追擊來搞搞閉包!頭疼的東西讓你不再頭疼! 一、函數也是引用類型的。 function f(){ console.log(not cha...

    Anleb 評論0 收藏0
  • 我的前端進階之路

    摘要:事件模型事件捕獲階段。事件到達目標元素觸發目標元素的監聽函數。的狀態值與狀態碼的狀態值未初始化還沒有調用方法。載入完成已經執行完成,已經接收到全部的響應內容。 前言 總括: 包含這三個月來碰到的一些覺得比較好的面試題,三個月沒怎么寫博客著實有些手癢,哈哈哈。7000余字,不成敬意2333 原文地址:我的前端進階之路 知乎專欄&&簡書專題:前端進擊者(知乎)&&前端進擊者(簡書) 博主...

    cloud 評論0 收藏0

發表評論

0條評論

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