JavaScript學習筆記——閉包—day three
阿新 • • 發佈:2018-11-20
目錄
什麼是閉包
當內部函式被儲存到外部時,將會生成閉包,生成閉包後,內部函式依舊可以訪問其所在的外部函式的變數。
兩個經典邏輯案例
例一:
function test() { var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { document.write(i + " "); } } return a; } var myArr = test(); for(var j=0;j<10;j++) { myArr[j](); }
執行結果:10 10 10 10 10 10 10 10 10 10
10個10,經過for迴圈後 i=10,而return a 只是返回了函式內容(document.write(i + " ");)這裡的 i 就一直是10。
例二:
這也是閉包的解決和防範方法:將 i(或者需要的變數等,但凡牽涉到索引的問題,一定要注意)變現。
function test(){ var arr=[]; for(i=0;i<10;i++) { (function(j){ arr[j]=function(){ document.write(j+" "); } }(i)) } return arr; } var myArr=test(); for(j=0;j<10;j++) { myArr[j](); }
執行結果:0 1 2 3 4 5 6 7 8 9
閉包的缺點
閉包會導致原有作用域鏈不釋放,造成記憶體洩漏(被佔用了,剩下的記憶體不是理論上應該多大的記憶體,並不是字面意思的洩漏)
閉包的作用
1.實現公有變數
如:函式累加器
function a(){ var num=100; function b(){ num++; console.log(num); } return b; } var add=a(); add(); add(); add();
2.可以做快取(儲存結構)
例1:
function test() {
var num = 100;
function a() {
num++;
console.log(num);
}
// a defined a.[[scope]] 0:testAo
// 1:GO
function b() {
num--;
console.log(num);
}
// a defined a.[[scope]] 0:testAo
// 1:GO
return [a, b];
}
var myArr = test();
myArr[0]();
// 代表a
// a doing a.[[scope]] 0:aAO
// 1:testAo(函式結束,AO依舊保留)
// 2:GO
myArr[1]();
// 代表b
// b doing b.[[scope]] 0:bAO
// 1:testAo(上一步更改過後的testAO)
// 2:GO
執行結果:101 100 兩個並列的函式使用的是同一個num,即一個testAO。
例二:
function eater() {
var food = "";
var obj = {
eat: function () {
console.log("i am eating " + food);
food = "";
},
push: function (myFood) {
food = myFood;
}
}
return obj;
}
var eaters = eater();
eaters.push('banana');
eaters.eat();
結果列印:i am eating banana 。這裡面的food就相當於一個儲存結構。物件裡面包含兩個函式,返回物件相當於返回兩個函式。兩個函式改變的始終都是同一個變數。
多個函式閉包,公用同一個變數。這種方式相當於快取。
3.可以實現封裝,屬性私有化
如:
function Wang(name,old){
var money=10000;
this.name=name;
this.old=old;
this.save=function(){
money++;
console.log(money);
}
}
var wang=new Wang('haha',46);
這裡的money就相當於一個私有屬性,不能直接訪問。
4.模組化開發,防止汙染全域性變數
名稱空間問題
管理變數,即使兩個函式中的變數名、函式名相同也不互相影響。開發的一個功能,以後會複用,就把它儲存到一個閉包裡面。
var name = '123';
var init=(function(){
var name='456';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())
var initWang=(function(){
var name='789';
function callName(){
console.log(name);
}
return function(){
callName();
}
}())