var func = function() { var a = 1; returnfunction() { a++; alert(a) } } var f = func() f() // 2 f() // 3 f() // 4 f() // 5
当退出函数时,局部变量a并没有消失,而是似乎一直在某个地方存活着。这是因为当执行var f = func()时,f返回了一个匿名函数的引用,它可以访问到func()被调用时产生的环境,而局部变量a一直处在这个环境里。既然局部变量所在的环境还能被外界访问,这个局部变量就有了不被销毁的理由。
1 2 3 4 5 6 7 8 9 10 11
var Type = {}
for (var i = 0; type = ['String', 'Array', 'Number']; i++) { (function(type){ Type[`is${type}`] = function(obj) { returnObject.prototype.toString.call(obj) === '[object ${type}]' } })(type) } Type.isArray([]) Type.isString('str')
1 2 3 4 5 6 7 8 9 10 11 12 13 14
// 对于相同的参数来说,每次都进行计算时一种浪费,引入缓存机制提高函数性能 var cache = {}; function () { var args = Array.prototype.join.call(arguments, ',') if (cache[args]) return cache[args] var result = 1 for (var i = 0; i < arguments.length; i++) { result = result * arguments[i] } return cache[args] = result } console.log(mult(1, 2, 3)) // 6 console.log(mult(1, 2, 3)) // 6 console.log(cache)
var mult = ( function(){ var cache = {}; returnfunction () { var args = Array.prototype.join.call(arguments, ',') if (cache[args]) return cache[args] // return cache[args] = calculate.apply(null, arguments) // null 即 windows 对象 return cache[args] = calculate(...arguments) } } )()
var calculate = function () { var result = 1 for (var i = 0; i < arguments.length; i++) { result = result * arguments[i] } return result } console.log(mult(1, 2, 3)) // 6 console.log(mult(1, 2, 3)) // 6
1 2 3 4 5 6 7 8
var report = function (src) { var imgs = [] returnfunction(src){ var img = new Image() imgs.push(img) img.src = src } }
使用闭包的同时比较容易形成循环引用,如果闭包的作用域链中保存着一些DOM节点,就有可能造成内存泄露。在IE浏览器中,由于 BOM 和 DOM 中的对象是使用 C++ 以 COM 对象的方式实现的,而 COM 对象的垃圾收集机制采用的是引用计数策略。在基于引用计数策略的垃圾回收机制中,如果两个对象之间形成了循环引用,那么这两个对象都无法被回收。
高阶函数
函数可以作为参数被传递
函数可以作为返回值输出
作为参数被传递
分离业务代码中变化和不变的部分
回调函数
异步请求
当一个函数不适合执行一些请求时,可以把这些请求封装成一个函数,“委托”给另外一个函数来执行
作为返回值输出
1 2 3 4 5 6 7 8 9 10 11 12
var getSingle = function(fn) { var ret returnfunction() { return ret || (ret = fn.apply(this, arguments)) } } var getScript = getSingle(function() { returndocument.createElement('script') }) var script1 = getScript() var script2 = getScript() alert(script1 === script2) // true