this
###闭包:什么是闭包?
征服 JavaScript 面试:什么是闭包?| Eric Elliott
你不仅仅应该了解闭包的机制,更应该了解闭包为什么很重要,以及能够很容易地回答出闭包的几种可能的应用场景。
JavaScript 里的函数能访问它们的:
1,this 和 arguments
2,局部变量和函数
3,外部函数的变量和函数
4,全部变量(包括DOM)
闭包的产生
函数被创建时其实就产生了闭包,通常我们将一个函数定义在另一个函数内部,称这个内部函数为闭包。
闭包的特点
JavaScript 采用了词法作用域,当闭包被传递到所在的词法作用域以外执行,它都会持有对原始定义作用域的引用,即使外部函数已经执行完毕,仍可通过闭包访问到外部函数作用域中的变量。
闭包的使用
1 | // 不用 return 的闭包 |
例子一:闭包中的局部变量是引用而非拷贝
1 | function foo(x) { |
例子二:多个闭包绑定同一个外部函数。
1 | var gAlertNumber, gIncreaseNumber, gSetNumber; |
例子三:当在一个循环中赋值函数时,这些函数将绑定同样的闭包
1 | function buildList(list) { |
解读:
我的理解,循环中定义的 item 和 i 实际上在外部函数 buildList 作用域下,不是循环体中的块级作用域。
当 buildList 执行完毕后,最后一次循环使得 item 的值为 item3,跳出循环后 i 的值为 4,而 list[4] 的值为 undefined。
修正:
方法一:
1 | // 循环体中使用了 let 定义块级变量 i 和 item。 |
方法二:
1 | // 通过IIFE传参的方式,把外部函数的变量闭包 |
闭包的应用场景
初级应用场景:在事件处理和回调函数中也常常会用到它。
高级应用场景:此外还有偏函数应用(partial applications)和柯里化(currying),以及其他函数式编程模式。
如果你不能回答这个问题,你只是个初级开发者。不管你实际上已经干这个多久了。
闭包的应用场景(一):对象中数据的私有化(返回对象)
当你使用闭包来实现数据私有化时,被封装的变量只能在闭包容器函数作用域中使用。
只有定义在闭包作用域中的方法才可以访问这些数据。
闭包的应用场景(二):创建有状态的函数(返回函数)
闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。在给定函数被多次调用的过程中,这些私有变量能够保持其持久性。
变量的作用域仅限于包含它们的函数,因此无法从其它程序代码部分进行访问。
不过,变量的生命周期是可以很长,在一次函数调用期间所创建所生成的值在下次函数调用时仍然存在。
正因为这一特点,闭包可以用来完成信息隐藏,并进而应用于需要状态表达的某些编程范型中。
1 | // Return a function that approximates the derivative of f |
debounce 防抖函数
1 | // 将会包装事件的 debounce 函数 |
throttle 节流函数