1.闭包
参考: 闭包,是真的美 作者:张建成 链接
什么是闭包?
闭包是指有权访问另一个函数作用域中变量的函数。内部的函数存在外部作用域的引用就会导致闭包。
闭包的缺点
内存泄漏
滥用闭包会导致内存泄露,因为内存空间使用完毕以后无法被自动回收,导致内存无法继续使用。
垃圾回收
JS具有自动垃圾回收机制。当我们创建函数、变量时会自动的分配相应的内存空间,当函数、变量不再使用后就变成垃圾。
- 标记清除
JS最常用垃圾回收方式,变量进入环境时候标为‘进入环境’,离开环境标为‘离开环境’
- 引用计数
跟踪记录每个值被引用的次数。
经典问题
js
// 下列函数输出的是 10 10 10 10 10 10 10 10 10 10
for(var i =0; i < 10; i++) {
setTimeout(function(){
console.log(i)
})
}
传统思路
js
// 下列函数输出的是 1 2 3 4 5 6 7 8 9 10
for(let i =0; i < 10; i++) {
setTimeout(function(){
console.log(i)
})
}
解释:setTimeout是异步函数(拓展:事件循环中会优先执行同步代码,再去消息队列中取任务执行。而不同的消息队列是有优先级区分的,过去W3C简单的将异步任务分为宏任务和微任务,但随着现代WEB的发展,浏览器已经将任务进行了更细的区分,延时任务。)而var定义的变量i被提升为全局变量,等事件循环去延时队列取任务是,回调函数里的i(即window.i)。而改用let以后,i有了自己的块级作用域,仅对当前循环有效,便解决了这个问题。
闭包思路
js
for(var i =0; i < 10; i++) {
(function(j){
setTimeout(function(){
console.log(j)
})
})(i)
}
闭包常用场景
防抖、节流
防抖:事件触发n秒后再执行回调,n秒内再次触发则重新计时
js
function debounded(callback, time, ...args) {
var timer = null
return function() {
// 存在计时器,返回
if (timer) clearTimeout(timer)
// 不存在则添加定时器
timer = setTimeout(()=>{
callback(args)
}, time)
}
}
适用:滚动事件、input监听
节流:单位时间内多次触发则只生效一次(第一次)
js
function throttle(callback, time, ...args) {
let lastTime = 0
return function() {
let now = Date.now()
if(now - lastTime > time) {
callback(...args)
lastTime = now
}
}
}
适用:高频点击
柯里化
把一个多参函数变成单参函数(利用闭包、arguments)
js
function curry(fn) {
// 得到从下标1开始的参数
const newArgs = Array.prototype.slice.call(arguments, 1);
let that = this
return function() {
let nowArgs = Array.from(arguments)
let totalArgs = [...newArgs, ...nowArgs]
if(totalArgs.length >= fn.length) {
return fn.apply(this, totalArgs)
} else {
totalArgs.unshift(fn)
return that.curry.apply(that, totalArgs)
}
}
}
应用场景
参数复用 例如需要打印某些日志,日期可以固定
jsconst addlog = (date, type, message) => { console.log(`${date},发生${type}类型错误,具体为${message}`) } const today = curry(addlog, '2099-01-30') run('未定义变量', 'Uncaught ReferenceError: a is not defined') // 2099-01-30,发生未定义变量类型错误,具体为Uncaught ReferenceError: a is not defined run('网络','network error') // 2099-01-30,发生网络类型错误,具体为network error
延迟执行
bind函数可以使用函数柯里化思想实现