Javascript之閉包以及閉包例項和常見面試題
阿新 • • 發佈:2018-11-19
一.什麼是閉包
高階程式設計三中:閉包是指有權訪問另外一個函式作用域中的變數的函式.可以理解為(能夠讀取其他函式內部變數的函式)
閉包的作用: 正常函式執行完畢後,裡面宣告的變數被垃圾回收處理掉,但是閉包可以讓作用域裡的 變數,在函式執行完之後依舊保持沒有被垃圾回收處理掉
二. 閉包的例項
// 建立閉包最常見的方式函式作為返回值 function foo() { var name = "kebi"; return function() { console.log(name); }; } var bar = foo(); bar(); //列印kebi --外部函式訪問內部變數
接下來通過一個例項來感受一下閉包的作用:
接下來實現一個計數器大家肯定會覺得這不是很簡單嗎
var count = 0;
function add() {
count = count + 1;
console.log(count);
}
add(); //確實實現了需求
//但是如果需要第二個計數器呢?
//難道要如下這樣寫嗎?
var count1 = 0;
function add1() {
count1 = count1 + 1;
console.log(count1);
}
add1(); //確實實現了需求
當我們需要更多地時候,這樣明顯是不現實的,這裡我們就需要用到閉包.
function addCount() {
var conut = 0;
return function() {
count = count + 1;
console.log(count);
};
}
這裡解釋一下上邊的過程: addCount() 執行的時候, 返回一個函式, 函式是可以建立自己的作用域的, 但是此時返回的這個函式內部需要引用 addCount() 作用域下的變數 count, 因此這個 count 是不能被銷燬的.接下來需要幾個計數器我們就定義幾個變數就可以,並且他們都不會互相影響,每個函式作用域中還會儲存 count 變數不被銷燬,進行不斷的累加
var fun1 = addCount();
fun1(); //1
fun1(); //2
var fun2 = addCount();
fun2(); //1
fun2(); //2
三.常見面試題
1. for 迴圈中列印
for (var i = 0; i < 4; i++) {
setTimeout(function() {
console.log(i);
}, 300);
}
上邊打印出來的都是 4, 可能部分人會認為列印的是 0,1,2,3
原因:js 執行的時候首先會先執行主執行緒,非同步相關的會存到非同步佇列裡,當主執行緒執行完畢開始執行非同步佇列, 主執行緒執行完畢後,此時 i 的值為 4,說以在執行非同步佇列的時候,打印出來的都是 4(這裡需要大家對 event loop 有所瞭解(js 的事件迴圈機制))
如何修改使其正常列印:(使用閉包使其正常列印)
//方法一:
for (var i = 0; i < 4; i++) {
setTimeout(
(function(i) {
return function() {
console.log(i);
};
})(i),
300
);
}
// 或者
for (var i = 0; i < 4; i++) {
setTimeout(
(function() {
var temp = i;
return function() {
console.log(temp);
};
})(),
300
);
}
//這個是通過自執行函式返回一個函式,然後在呼叫返回的函式去獲取自執行函式內部的變數,此為閉包
//方法發二:
for (var i = 0; i < 4; i++) {
(function(i) {
setTimeout(function() {
console.log(i);
}, 300);
})(i);
}
// 大部分都認為方法一和方法二都是閉包,我認為方法一是閉包,而方法二是通過建立一個自執行函式,使變數存在這個自執行函式的作用域裡
2.真實的獲取多個元素並新增點選事件
var op = document.querySelectorAll("p");
for (var j = 0; j < op.length; j++) {
op[j].onclick = function() {
alert(j);
};
}
//alert出來的值是一樣的
// 解決辦法一:
for (var j = 0; j < op.length; j++) {
(function(j) {
op[j].onclick = function() {
alert(j);
};
})(j);
}
// 解決辦法二:
for (var j = 0; j < op.length; j++) {
op[j].onclick = (function(j) {
return function() {
alert(j);
};
})(j);
}
//解決方法三其實和二類似
for (var j = 0; j < op.length; j++) {
op[j].onclick = (function() {
var temp = j;
return function() {
alert(j);
};
})();
}
//這個例子和例子一幾乎是一樣的大家可以參考例子一
3.閉包的缺陷:
通過上邊的例子也發現, 閉包會導致記憶體佔用過高,因為變數都沒有釋放記憶體