1. 程式人生 > >js閉包深入理解

js閉包深入理解

1.定義和理解

首先在高階程式設計中對於閉包概念是這樣定義的:“閉包是指有許可權訪問另一個函式作用域中的變數的函式。“

意思就是函式a能訪問到函式b作用域下的變數那麼函式a就是閉包,在網路上有些文章指出閉包有兩個條件:

1.函式巢狀,內部函式要用到外部函式的區域性變數 2、內部函式必須返回

同時也有些人認為不要返回內部函式也可以稱之為閉包,我們從高階程式設計中對於閉包概念定義來分析就是即使沒有返回內部函式也是閉包。

我們可以參考一下阮一峰老師對閉包的理解:(由於在Javascript語言中,只有函式內部的子函式才能讀取區域性變數,因此可以把閉包簡單理解成"定義在一個函式內部的函式"。所以,在本質上,閉包就是將函式內部和函式外部連線起來的一座橋樑)

2.環境變數

要理解閉包,首先必須理解Javascript特殊的變數作用域。在js中變數的作用域無非就是兩種:全域性變數和區域性變數。區域性變數寫在函式體內,區域性變數省略了var 也就預設成為了全域性變數!

var a=15 // 變數a定義在函式外面也就是全域性變數在該js中任何地方都可以訪問
function out() {
  console.log(a) // 函式out裡面是可以直接訪問全域性變數
}
out()

在這裡a就是全域性變數,如果在nodejs中還有頂層物件,在瀏覽器環境指的是window物件,在Node指是的global物件,ES5之前中,頂層物件的屬性與全域性變數是等價的。

ES6規定,var命令和function命令宣告的全域性變數,依舊是頂層物件的屬性;let命令、const命令、class命令宣告的全域性變數,不屬於頂層物件的屬性這裡就不再陳述。

var a=15 // 變數a定義在函式外面也就是全域性變數在該js中任何地方都可以訪問
function out() {
  var b=20 // 變數b定義在函式out裡面,變數是區域性變數
  console.log(a) // 函式out裡面是可以直接訪問全域性變數
}
out()
console.log(a)//在這裡列印變數a是可以訪問到的
console.log(b)//在這裡列印變數b是無妨訪問的

在這個例子中我們可以看到函式out可以訪問全域性變數a,但是在函式外部是訪問不到out函式裡面的區域性變數b

var a=15 // 變數a定義在函式外面也就是全域性變數在該js中任何地方都可以訪問
function out() {
  var b=20 // 變數b定義在函式out裡面,變數是區域性變數
  c=30// 變數c沒有使用var,所有c也是全域性變數
  console.log(a) // 函式out裡面是可以直接訪問全域性變數

}
out()
console.log(a)//在這裡列印變數a是可以訪問到的
console.log(c)//在這裡列印變數是才可以訪問到的
console.log(b)//在這裡列印變數b是無妨訪問的

這個例子就是區域性變數省略了var 也就預設成為了全域性變數!所有大家在定義變數的時候要注意

總結:Javascript語言的特殊之處,就在於函式內部可以直接讀取全域性變數。另一方面,在函式外部自然無法讀取函式內的區域性變數。

3.外部讀區域性變數(閉包) 

在我進行程式設計過程中出於種種原因,我們有時候需要得到函式內的區域性變數。但是,由於變數的作用域,正常情況下,這是辦不到的,只有通過變通方法才能實現。

function a() {
  var x=10;
  function b() {
    console.log(x)
  }
  b()
}
a()

在這個例子中函式b要是想訪問函式a裡面的變數x,如何直接把函式b放到函式a外面,函式b裡面是輸出不了變數x,所有我們將函式b放到了函式a裡面,然後執行函式b,這個時候函式b就可以正常訪問到函式a的變數x,因為函式b位於函式a裡面所以是可以訪問到函式a作用域下的變數。

function f1(){
  var n=999;
  function f2(){
    console.log(n)
  }
  return f2;
}
var result=f1();
result()

這裡給大家展示一個阮一峰老師的一個例子:既然f2可以讀取f1中的區域性變數,那麼只要把f2作為返回值,我們不就可以在f1外部讀取它的內部變量了嗎!

上面程式碼中的f2函式,就是閉包,我的理解就是:閉包,指的是在函式裡的函式。(其實閉包就是被巢狀的那個函式)

4.閉包的作用

閉包可以讀取函式內部的變數,可以讓變數的值始終保持在記憶體中。

通過閉包我們可以在函式外部讀取函式內部的變數,簡單來說閉包就是將函式的外部和內部進行了連線