>[success] # 闭包的作用 ~~~ 1.闭包的作用 --- 缓存数据,延长作用域链 ~~~ >[danger] ##### 缓存数据案例 ~~~ 1.需求:现在需要一个参数累积相乘的方法,但是如果出现的结果, 期望可以直接从缓存中取,举个例子'1*2*3' 已经算过值了,不希望 在走一遍'1*2*3'的逻辑 ~~~ * 不利用闭包的思想做 ~~~ let cache = {} let mult = function (...args) { const key = args.toString() if(cache[key]){ console.log('走了缓存') return cache[key] } let count = 1 args.forEach(item=>{ count = count * item }) // 赋值后会返回赋值的值 return cache[key] = count } console.log(mult(1,2,3)) console.log(mult(1,2,3)) 打印结果: 6 走了缓存 6 ~~~ * es5 ~~~ var cache = {} let mult = function(){ // 输入任一参数 var key = Array.prototype.join.apply(arguments) if(cache [key]){ console.log('缓存') return cache[key] } var count = 1 for(var i=0,num;num = arguments[i++];){ count*=num } return cache[key] = count } console.log(mult(1,2,3)) console.log(mult(1,2,3)) ~~~ * 简洁点写法 ~~~ const cache = {} let mult = function(){ // 缓存 就需要有key 把参数变成 逗号 分割形式 const arry = [].slice.call(arguments) const key = arry.join() if(mult[key] === undefined){ mult[key] = arry.reduce((acc,curr) => {return acc*curr},1) } return mult[key] } ~~~ * 利用闭包的思想来做 ~~~ 1.将需要的缓存对象一并放进 '方法中',这样就可以方法复用 ~~~ ~~~ let mult = (function () { let cache = {} return function(...args){ const key = args.toString() if(cache[key]){ console.log('走了缓存') return cache[key] } let count = 1 args.forEach(item=>{ count = count * item }) // 赋值后会返回赋值的值 return cache[key] = count } })() console.log(mult(1,2,3)) console.log(mult(1,2,3)) 打印结果: 6 走了缓存 6 ~~~ * 再次改进 ~~~ 1.下面的好处是将搭函数中的一些代码块队里出来封装到小函数中,可以 方便代码的复用或者也起到了代码的注释的作用 ~~~ ~~~ let mult = (function () { let cache = {} const calculate = function (args) { let count = 1 args.forEach(item=>{ count = count * item }) return count } return function(...args){ const key = args.toString() if(cache[key]){ console.log('走了缓存') return cache[key] } // 赋值后会返回赋值的值 return cache[key] = calculate(args) } })() console.log(mult(1,2,3)) console.log(mult(1,2,3)) 打印结果: 6 走了缓存 6 ~~~ * 利用点es6的知识 ~~~ let mult = (function () { let cache = {} let f = (accumulator, currentValue)=>a*b return (...args)=>{ let key = args.toString() if(Reflect.has(cache,key)){ console.log('1') return cache[key] } return cache[key] = args.reduce(f) } })() console.log(mult(1,2,3)) console.log(mult(1,2,3)) 打印结果: 6 1 6 ~~~ >[danger] ##### 延续局部变量寿命 ~~~ 1.前端需要给后台上传数据的时候我们都知道需要使用'img'属性 可以实现原因既可以跨域有可以方便传输如下: 2.下面的report函数并不是每一次都成功发起了HTTP请求。丢失数据的原因是 img是report函数中的局部变量,当report函数的调用结束后,img局部变量随即 被销毁,而此时或许还没来得及发出HTTP请求,所以此次请求就会丢失掉。 ~~~ ~~~ function report(sev, msg){ var img = new Image(); img.src = "log.php?sev=" + encodeURIComponent(sev) + "&msg=" + encodeURIComponent(msg); } ~~~ * 利用闭包修正问题 ~~~javascript var report = (function(){ var imgs = []; return function( src ){ var img = new Image(); imgs.push( img ); img.src = src; } })(); ~~~ >[danger] ##### 利用闭包做一个类型判断 ~~~ 1.相比把函数当作参数传递,函数当作返回值输出的应用场景也有很多。 让函数继续返回一个可执行的函数,意味着运算过程是可延续的 ~~~ * 正常写的类型判断,有多少写多少 ~~~ var isString = function( obj ){ return Object.prototype.toString.call( obj ) === '[object String]'; }; var isArray = function( obj ){ return Object.prototype.toString.call( obj ) === '[object Array]'; }; var isNumber = function( obj ){ return Object.prototype.toString.call( obj ) === '[object Number]'; }; ~~~ * 利用闭包 ~~~ 1.实际上,这些函数的大部分实现都是相同的,不同的 只是Object.prototype.toString.call(obj)返回的字符串。为了避免多余的代码,= 可以把这些字符串作为参数提前传入isType函数。代码如下: 2.下面这种写法是 thunk 函数 一种体现,它的基本思路都是接收一定的参 数,会生产出定制化的函数,最后使用定制化的函数去完成想要实现的功能 ~~~ [thunk 函数](https://zhuanlan.zhihu.com/p/404060484) ~~~ 1.var isType = function( type ){ return function( obj ){ return Object.prototype.toString.call( obj ) === '[object '+ type +']'; } }; var isString = isType( 'String' ); var isArray = isType( 'Array' ); var isNumber = isType( 'Number' ); console.log( isArray( [ 1, 2, 3 ] ) ); // 输出:true ~~~ * 利用循环批量注册 ~~~ var Type = {}; for ( var i = 0, type; type = [ 'String', 'Array', 'Number' ][ i++ ]; ){ (function( type ){ Type[ 'is' + type ] = function( obj ){ return Object.prototype.toString.call( obj ) === '[object '+ type +']'; } })( type ) }; Type.isArray( [] ); // 输出:true Type.isString( "str" ); // 输出:true ~~~