闭包算是在 JS 中常听到,却不容易使用的一个方法,更多状况是不小心用出来,~~因此出 bug ~~
在介绍闭包之前,先来看看下面范例:
function randomString(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
function getData() {
var demoData = [];
for (let i = 0; i < 1000; i++) {
demoData.push(randomString(1000))
}
}
getData();
randomString
是一个会根据设定执行数次,产生乱码字串的方法,而这乱码字串会藉由 return result
回传,最後又在 push 至 demoData 变数上。
使用 chrome 无痕模式来观察 Memory ,可以发现在执行上述程序码时,记忆体使用了 1.3 MB
再来执行另外一段非常相近的程序码,来看看他的记忆体使用量:
function randomString(length) {
var result = '';
var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
var demoData = [];
function getData() {
for (let i = 0; i < 1000; i++) {
demoData.push(randomString(1000))
}
}
getData();
可以发现这个范例记忆体增使用量将近 21MB ,这是因为第二个范例 demoData
变数是被放在外层也就是全域( window)底下,而 demoData
变数此时是能在被呼叫、使用的。
而第一个范例中, demoData
是在函示里头, demoData
变数则会跟着 getData
执行完毕时,一同被释放记忆体,此时 demoData
也是无法被呼叫的,因此两者记忆体落差十分大。
之所以要先讲这一段是因为,记忆体可以说是闭包的一个重点。
接下先来看看闭包的一个简单范例
function openFn() {
let num = 10
function ClosureFn(newNum) {
num = num + newNum
return num
}
//函示内 return 函示就会变成 『闭包』
return ClosureFn
}
const useClosure = openFn()
console.log(useClosure(10)) //20
console.log(useClosure(10)) //30
console.log(useClosure(10)) //40
在上面范例中 ClosureFn
其实就是闭包,若要执行这个闭包可以直接使用 openFn()(100)
其就会被执行,不过一般来说我们不会直接使用两个 ()()
小刮号做执行,而是像上面范例中使用 openFn()
并且再用一个变数来做指向。
而上面有提到记忆体是闭包的重点,关於这一点我们可以看看连续执行 useClosure()
後回传的值会不断叠加,然而 ClosureFn
闭包函示内部虽然没有 let num = 100
,不过闭包内部会因为 num = num + newNum
这段程序码,有使用到 num
变数,因此按照作用域的规则,会访问(参考)外层函式的 let num
变数,因为这个访问(参考)的动作,就会让 num
变数的记忆体『不被释放』,因此当正是因为这个『不被释放』,我们使用 useClosure(10)
的值才可以不断被叠加。
这边也试者使用图片来增加对闭包的理解:
之所以要使用闭包,就是因为可以透过不同变数、常数,让闭包回传资料各自独立,某些需要重复使用程序码的状况就可以使用闭包,例如
function openFn() {
let num = 10
function ClosureFn(newNum) {
num = num + newNum
return num
}
//函示内 return 函示就会变成 『闭包』
return ClosureFn
}
const useClosure1 = openFn()
console.log(useClosure1(10))
console.log(useClosure1(10))
const useClosure2 = openFn()
console.log(useClosure2(100))
console.log(useClosure2(100))
下篇则会介绍闭包延伸运用。
>>: .NET Core第12天_服务依赖注入_IoC容器生命周期_ConfigureServices
攻击者会使用Trojan horses(木马程序)来诱骗使用者在电脑上执行预先设计的操作, 一旦木马...
战略资讯系统 中台架构其实是一种整体资讯架构订定的思维,其目的是为了迎接企业不断创新的挑战,在『变是...
wiki 说明页:回归分析 想了解详细的说明,请见wiki或者其他参考资料。 或者也可以直接看下面,...
“The meaning of life is that it stops.” ― Franz K...
虽然storyboard是个对初学者比较方便使用的东西,但是当你有很多元件要用,修改来讲的话就就会比...