Js的闭包
引子: js必须要了解他的闭包
https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
https://stackoverflow.com/questions/111102/how-do-javascript-closures-work/111111#111111
闭包
谈到了函数就不能不谈闭包, 这个是js特色, 为啥用闭包? 其实是为了封闭对象的私有属性.
为啥用闭包, 这个实在是忘记了, 还要再看一下下, 为啥不是简单的使用函数, 而是要用闭包.
- 明白了, 闭包拥有可以访问私有属性的方法了.
- 闭包返回一个对象更有意义, 一般情况下.
- 这个对象可以访问闭包函数拥有的私有属性, 这些属性外部无法访问.
- 如果我就是定义一个函数, 用来返回对象, 那么我还要执行这个函数. 来得到他返回的对象, 因此, 这个函数的函数名就毫无意义, 把定义这个函数和执行这个函数合二为一之后, 就是闭包了.
- 闭包其实就是直接执行一个函数, 得到返回的对象, 这个对象还有自己的私有属性, 这些属性定在了这个直接执行的闭包函数里面.
闭包的实际案例
https://stackoverflow.com/questions/3288893/why-do-we-have-closures-in-javascript
- module 可以做分包, 参见我8.28的blog
- 可以memorization, 简单地说就是缓存计算结果 参见我8.29的blog
- currying, 递归和迭代
let和闭包
let确实在很多时候可以替代闭包. 尤其是:
- timeout这一类的异步执行.
- 循环体里面执行函数, 循环值是函数的参数. 如果不用let也不用闭包, 最后只有循环的最后一个值传入了.
var funcs = [];
for (var i = 0; i < 3; i++) { // let's create 3 functions
funcs[i] = function() { // and store them in funcs
console.log("My value: " + i); // each should log its value.
};
}
for (var j = 0; j < 3; j++) {
funcs[j](); // and now let's run each one to see
}
//实际输出:
My value: 3
My value: 3
My value: 3
分析:
function() { // 这里并没有传入参数.
console.log("My value: " + i); // 这是一个函数, 这个函数, 里面的i就是一个变量, i最终的值就是3.
};
//即便改为下面这样也是不行的:
funcs[i] = function(i) { // and store them in funcs
console.log("My value: " + i); // each should log its value.
};
//原因是调用的时候, 并没有传入i.
My value: undefined
My value: undefined
My value: undefined
解决方案有三个, 大家看原文吧, 确实是很精妙: https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example
关于闭包之前的blog有不少:
- 17 - 12 - 03 js精华
- 17 - 12 - 16 对象和迭代
- 17 - 12 - 19 node
- 18 - 05 - 17 多语言
- 18 - 08 - 28 js模块化
- 18 - 09 - 02 js生命
2019-01-19对闭包更多的思考
- 当年的js没有module, 没有promise, 没有let, 只有闭包.
- 闭包确实是funcitonal的思路, 很容易构造高阶函数, 而且还很规整.
- 闭包一定程度上缓解了括号地狱. 但是括号有害这个观点是python之后才出现的. 而在当年, 像lisp一样去构建高阶函数会被认为是一个很优雅的事情, 就像后来出现的那个傻乎乎的addlistener一样. 很多时候, 人们很难分清改进和改退, 马克思说事务曲折发展, 真的很对.