閉包的定義:閉包是指有權訪問另一個函數作用域中的變數的函數 --《JavaScript 高級程式設計》。 如何理解這句話:其實就是指在函數a外面能夠訪問函數a裡面的函數b。 例如: 1 function a () { 2 var v = 123; 3 function b() { 4 console ...
閉包的定義:閉包是指有權訪問另一個函數作用域中的變數的函數 --《JavaScript 高級程式設計》。
如何理解這句話:其實就是指在函數a外面能夠訪問函數a裡面的函數b。
例如:
1 function a () { 2 var v = 123; 3 function b() { 4 console.log(v); 5 } 6 return b; 7 } 8 9 var b = a(); 10 b(); // 123
執行函數a時把函數b返回,此時函數b就保存到了a的外面,這時候就可以在a函數的外部對b進行訪問。
相關知識點:js作用域鏈
執行原理:
1、首先在預編譯全局代碼時,生成GO
GO {
a: function a() {...},
b: undefined
}
2、執行 var b = a(); 此時對a函數進行預編譯並創建a 函數的AO
AO {
v: undefined,
a: undefined,
b: function b() {...}
}
3、創建a函數的作用域鏈
a.[[Scopes]] = [AO, GO];
4、由於函數的提升,會在a函數進行預編譯的時候創建b函數的AO
b AO {}
b.[[Scopes]] = [AO(b), AO(a), GO]
5、執行 var v = 123; 在js預編譯中提到由於var v 的聲明已經得到了提升,所以此時只執行v = 123;對AO里的v 進行賦值。
AO {
v: 123,
a: undefined,
b: function b() {...}
}
6、之後將函數b返回,此時a函數執行完畢,a函數對應的AO理應銷毀,但是由於在b函數中又對a函數的AO中的變數進行應用,所以a函數的AO不能被垃圾回收機制銷毀,但是會跟a函數斷開聯繫,當a函數再次執行,會重新創建一個a函數的AO。
7、在全局變數中使用b 接收函數a的返回,此時GO變為
GO {
a: function a() {...},
b: function b() {...}
}
8、全局裡的b
在b函數中列印v變數,由於b函數的AO中沒有v變數,所以順著作用域鏈往上找,在a的AO中找到v並列印。
閉包優缺點:
優點:
1、屬性的私有化,在b返回後,處理b函數中能對v進行操作,其它地方都不能對v進行操作。
2、防止變數污染。
缺點:
容易造成記憶體泄漏,因為如果後期不對全局中的b進行處理(例如:賦值為null),a函數的AO 會一直存在於記憶體中,如果多次調用a函數,容易導致記憶體中的垃圾數據越來越多造成記憶體泄漏。