1. 閉包是什么?
function A () { // chrome認為的閉包是A函數(shù)
var num = 1
return function B () {
console.log(num)
}
}
var C = A ()
// 函數(shù)A中的變量num被全局函數(shù)C引用著,以至于不會被垃圾回收機制回收
C() // 1 // 大多數(shù)書籍理解的閉包是C函數(shù)
在A函數(shù)中嵌套B函數(shù),B函數(shù)訪問A函數(shù)中的變量。將A函數(shù)復(fù)制給C函數(shù)并執(zhí)行。
那么在大多數(shù)的理解中,包括許多著名的書籍,文章里都以函數(shù)C的名字代指這里生成的閉包。而在chrome中,則以執(zhí)行上下文A的函數(shù)名代指閉包。
而我的理解是:閉包更準確的說是一項技術(shù)或者一個特性:只要運用具備阻止垃圾回收機制回收和突破作用域鏈限制的技術(shù),就是閉包。像是《JavaScript權(quán)威指南》打的比方,像是把變量包裹了起來,形象的稱為“閉包”。
如果非要指明哪個函數(shù)是閉包的話,我愿意將A函數(shù)稱為定義閉包的函數(shù),C函數(shù)為執(zhí)行閉包的函數(shù)。
2 生成閉包的條件是什么?
function foo() { // 定義閉包
var a = 10;
function baz() {
console.log(a);
}
baz(); // 被確認創(chuàng)建閉包
}
baz();
a. 在函數(shù)內(nèi)部創(chuàng)建新的函數(shù);
b. 新的函數(shù)在執(zhí)行時,訪問了函數(shù)的變量對象。
c. 閉包是在函數(shù)被調(diào)用執(zhí)行的時候才被確認創(chuàng)建的。
一句話總結(jié):==函數(shù)中閉包判定的準則,即執(zhí)行時是否在內(nèi)部定義的函數(shù)中訪問了上層作用域的變量。==
3. 閉包的作用是什么?
閉包,阻止垃圾回收機制。
閉包,突破作用域鏈接。
4 閉包的應(yīng)用
模塊模式
《你不知道的JS中》的示例:
function coolModule () {
// 私有變量和函數(shù)
var something = 'cool';
var another = [1, 2, 3]
function doSomething () {
console.log(something)
}
function doAnother () {
console.log(another.join('!'))
}
// 公開方法
return {
doSomething,
doAnother
}
})
var foo = coolModule ()
foo.doSomething() // cool
foo.doAnother() // 1!2!3
模塊模式需要具備兩個必要條件:
1.必須有外部的封閉函數(shù),該函數(shù)必須至少被調(diào)用一次(每次調(diào)用都會創(chuàng)建一個新的模塊實例)。
2.封閉函數(shù)必須返回至少一個內(nèi)部函數(shù),這樣內(nèi)部函數(shù)才能在私有作用域中形成閉包,并且可以訪問或者修改私有的狀態(tài)。
什么時候使用模塊模式?
如果必須創(chuàng)建一個對象并一某些數(shù)據(jù)對其進行初始化,同時還要公開一些能夠訪問這些私有數(shù)據(jù)的方法,那么就可以使用模塊模式。
哪些地方有用到模塊模式?
最典型的就是JQuery庫,jQuery和$標識符就是JQuery模塊的公共API,但它們本身都是函數(shù)(由于函數(shù)也是對象,它們本身也可以擁有屬性)
以后單獨拿一個章節(jié),來具體講講現(xiàn)在的模塊化和未來的模塊化機制。
柯里化
具體的內(nèi)容在函數(shù)的柯里化的章節(jié)中詳細分析。
面試題
- 防抖和節(jié)流
戳此傳送門
- 定時器
for (var i = 1; i <= 5; i++) {
setTimeout(function timer() {
console.log(i); // 5次6
}, i * 1000);
}
輸出6的原因是:被封閉在一個共享的全局作用域中,實際上只有一個i。
for (var i = 1; i <= 5; i++) {
(function (j) {
setTimeout(function timer() {
console.log(j); // 依次輸出1至5
}, i * 1000);
})(i)
}
依次輸出1-5的原因是:在迭代內(nèi)部使用IIFE(立即表達函數(shù))為每個迭代生成一個新的作用域,將外部變量的值傳遞進去并被引用(阻止垃圾回收機制回收),使得每個回調(diào)函數(shù)都能訪問到正確值的變量。
- jn-toast組件認識閉包