大家好,欢迎来到IT知识分享网。
{ var x = 100 function fn (y) { var x = 200 return function(y) { console.log(y + x++) } } var f = fn() f(10) f(20) } { let x = 5 function fn(x) { return function(y) { console.log(y + (++x)) } } let f = fn(6) f(7) // f(7) fn(18)(9) f(10) console.log(x) } { let a = 0, b = 0 function A(a) { A = function(b) { console.log(a + b++) } console.log(a++) } A(1) A(2) } // 简述你对闭包的理解,以及其优缺点? // + 基本介绍:ECStack、EC、VO、AO、SCOPE、SCOPE-CHAIN、GC // + 优缺点:保存和保护、性能消耗(内存泄露) // + 实战应用: // - 项目实战应用:循环事件绑定(突出:事件委托)、let和var // - 插件组件封装:JS高级编程技巧(单例设计模式、惰性函数、科里化函数、compose组合函数) // - 源码阅读应用:lodash源码(函数的防抖和节流)、JQ源码、redux、react-redux(高阶组件) // - ... // + 自己的思想和理解(一句话概括) // 闭包的概念:在一个函数执行完后,它内部的变量会被释放,但是如果其他的函数有引用它内部的变量,就形成了闭包 // 闭包的优点: // 1. 读取另一个函数作用域中的变量。 // 2. 保存数据,因为闭包的数据不会被释放,所以可以保存数据 // 3. 封装对象的私有属性和私有方法(对外提供访问数据的接口) // 闭包的缺点:过度使用闭包可能会导致内存占用过多的问题,在IE浏览器中可能会导致内存泄露 // 产生闭包的场景: // 1. 立即执行函数(IIFE) // 2. 返回一个函数 // 3. 定时器、事件监听、AJAX请求等的回调 // 4. 作为函数参数传递 // 闭包的应用:早期的模块化(IIFE)、防抖节流(返回一个函数)、科里化函数(返回一个函数)、compose组合函数(返回一个函数)、循环事件绑定
## 应用
/** * JS高阶编程技巧:利用闭包的机制,实现出来的一些高阶编程技巧 * + 模块化思想 * + 惰性函数 * + 科里化函数 * 1. 高阶组件 -> React * 2. 防抖、节流 * 3. bind * 4. ... * + compose组合函数 * + ... */ // 模块化思想 单例 -> AMD(require.js) -> CMD(sea.js) -> CommonJS(Node) -> ESModule // 对象的特点:每一个对象都是一个单独的堆内存空间(单独的实例 -> Object),这样即使多个对象中的成员名字相同,也互不影响 // 每一个对象都是一个单独的实例,用来管理自己的私有信息,即使名字相同,也互不影响,其实这就是 “JS中的单例设计模式” // ------------------- 高级单例模式:闭包 + 单例的结合,样式最早期的JS模块化思想 /* var moduleA = (function () { var time = Date.now() function queryData() {} return { time, queryData } })() */ /* function getCss (el, attr) { if (window.getComputedStyle) { return window.getComputedStyle(el)[attr] } return el.currentStyle(attr) } */ // ------ 优化思想:第一次执行 getCss 方法时,已经知道是否兼容了,再次执行的 getCss 方法,不想再处理判断兼容的逻辑了,这种思想就是“惰性思想” /* function getCss (el, attr) { if (window.getComputedStyle) { getCss = function getCss (el, attr) { return window.getComputedStyle(el)[attr] } } else { getCss = function getCss (el, attr) { return el.currentStyle(attr) } } return getCss(el, attr) } const body = document.body console.log(getCss(body, 'height')) console.log(getCss(body, 'width')) console.log(getCss(body, 'margin')) */ // 函数科里化: /* function curring (x) { return function (...args) { return args.reduce((prev, next) => prev + next, x) } } console.log(curring(10)(20)) console.log(curring(10)(20, 30)) */ // compose组合函数 /* const add = x => x + 1 const multi = x => x * 3 const divide = x => x / 2 function compose (...funcs) { return function (x) { if (funcs.length === 0) return x return funcs.reduceRight((prev, next) => { if (typeof next !== 'function') return prev return next(prev) }, x) } } const operate = compose(divide, multi, add) console.log(operate(0)) */ function add (...params) { const proxy = (...args) => { params = params.concat(args) return proxy } proxy.toString = () => params.reduce((prev, next) => prev + next) return proxy } console.log(add(1)(2)(3)) console.log(add(1, 2, 3)(4)) console.log(add(1)(2)(3)(4, 5))
### 防抖节流
function debounce (fn, delay, immediate) { let timer = null // return function (...args) { // timer && clearTimeout(timer) // timer = setTimeout(() => { // fn(...args) // }, delay) // } return function (...args) { let context = this if (immediate) { fn.call(context, ...args) immediate = false } timer && clearTimeout(timer) timer = setTimeout(function () { fn.call(context, ...args) }, delay) } } function throttle (fn, delay, immediate) { let timer = null return function (...args) { let context = this if (timer) return timer = setTimeout(function () { fn.call(context, ...args) timer = null }, delay) } } function fn (e) { console.log('resize', e) } // window.addEventListener('resize', debounce(fn, 1000)) window.addEventListener('resize', throttle(fn, 1000))
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://yundeesoft.com/58886.html