作用域鏈
要學習閉包筷笨,首先要了解作用域鏈
作用域鏈:環(huán)境對象中定義的變量,會放到作用域中,形成一個鏈式結構。
定義三個變量 a b c 使其在不同的作用域
var a = 10;
function F() {
var b = 20;
//內部函數(shù):函數(shù)內部定義的函數(shù)
function N() {
var c = 30;
return a + b + c;
}
return N();
}
//驗證N中是否都能使用所有的鏈上變量
console.log(F());//60
在變量 c 的作用域中叮趴,可以調用到 a b 在 b 的作用域中,可以調用到 a
但是反向就不能實現(xiàn)权烧,a 的作用域中無法調用 b c 眯亦,b的作用域中 無法調用 c
如果我們想在變量作用域中訪問其子作用域中定義的變量,要怎樣實現(xiàn)呢般码?閉包的使用能解決這個問題
利用閉包突破作用域鏈
首先來看閉包的概念
閉包的原理就是在被訪問的變量a的作用域中創(chuàng)建一個函數(shù)板祝,將需要訪問的變量當做新創(chuàng)建的函數(shù)返回值宫静,再將函數(shù)定義給最外層的變量b,就能通過執(zhí)行變量b來訪問到變量a
原理如圖:
代碼如下:
//第一種寫法
var a = 10;
function F() {
var b = 20;
function N(){
return b
}
return N;
}
var M = F();
console.log(M());
// 原理一樣,寫法不一樣囊嘉,第二種寫法
var inner;
var a = 10;
function F() {
var b = 20;
function N(){
return b
}
inner = N;
}
F();
console.log(inner());
不過需要注意:
閉包會常駐內存温技,使用需要謹慎
閉包的概念清楚了,下面來講一下閉包的應用
閉包的應用1
循環(huán)中的閉包
我們可以試著將函數(shù)里循環(huán)中的每一個變量拿出來扭粱。
敲一下代碼:
function F() {
var arr = [];
for (var i = 0; i < 3; i++) {
arr[i] = function(){
return i;
};
}
return arr;
}
var str = F();
console.log(str[0](), str[1](), str[2]());//3 3 3
咦?什么鬼震檩,怎么出現(xiàn)了三個一樣的數(shù)
分析一下琢蛤,不難發(fā)現(xiàn),arr[i]中保存的是 i 抛虏, i 是相當于直接定義在 F 函數(shù)的作用域中博其,執(zhí)行完 F 函數(shù) i 的值直接就已經(jīng)變?yōu)?3 ,這樣迂猴,我們就應該在循環(huán)的時候慕淡,就把數(shù)組里的值保存下來,這樣就對了
閉包本身不保存上一作用域中變量的值沸毁,當使用時是去上面的作用域中查找相同名字變量峰髓,使用最近那一層作用域中的變量
修改代碼如下:
function F() {
var arr = [];
for (var i = 0; i < 3; i++) {
arr[i] = (function(x){
return function(){
return x;
};
})(i);
}
return arr;
}
var str = F();
console.log(str[0](), str[1](), str[2]());//0 1 2
也有原理圖,在此:
這樣就能保存到我們想要的數(shù)據(jù)了
閉包的應用2
getter 和 setter
有時候息尺,為了變量的安全考慮携兵,我們一般會不讓變量直接被訪問到
就可以利用閉包來實現(xiàn)
看看代碼:
var setNum;
var getNum;
(function(){
var num = 0;
//setter方法
setNum = function(x) {
//安全的考慮
if (typeof x === "number") {
num = x;
}
};
//getter方法
getNum = function() {
return num;
};
})();
console.log(num);//0
setNum(100);
console.log(getNum());//100
這樣的話,直接訪問 num 是訪問不到的搂誉,同時要修改 num 的值也不能直接修改徐紧,通過閉包的方法,我們還能控制賦給變量新賦值的類型
閉包的應用3
迭代器
迭代: 一個一個尋找下一個目標
知道遍歷簡單的數(shù)組炭懊,以后便利的數(shù)據(jù)結構可能比較復雜
使用“下一個是誰”的想法去遍歷
代碼如下:
var arr = [1,2,3,4,5];
function setUp(x) {
var i = 0;
return function (){
if(x.length == i-1){
i = 0;
}
return x[i++];
}
}
var next = setUp(arr);
console.log(next());//1
console.log(next());//2
console.log(next());//3
console.log(next());//4
console.log(next());//5
console.log(next());//undefined
console.log(next());//1
console.log(next());//2
這樣就實現(xiàn)了迭代的方法并级,一次一次找到下一個值