这是我参与「第四届青训营 」笔记创作活动的第2天。
在组队群里我们对月影老师课上的代码进行了分析、讨论。
代码如下:
function consumer(fn, time){
let tasks = [],
timer;
return function(...args){
tasks.push(fn.bind(this, ...args));
if(timer == null){
timer = setInterval(() => {
tasks.shift().call(this)
if(tasks.length <= 0){
clearInterval(timer);
timer = null;
}
}, time)
}
}
}
function add(ref, x){
const v = ref.value + x;
console.log(`${ref.value} + ${x} = ${v}`);
ref.value = v;
return ref;
}
let consumerAdd = consumer(add, 1000);
const ref = {value: 0};
for(let i = 0; i < 10; i++){
consumerAdd(ref, i);
}
前置知识:
-
闭包
-
高阶函数
闭包(Closure)
我们先看一下在计算机科学中对闭包的定义(维基百科):
闭包(Closure),又称词法闭包(Lexical Closure)或函数闭包(function closures);
是在支持 头等函数 的编程语言中,实现词法绑定的一种技术;
闭包跟函数最大的区别在于,当捕捉闭包的时候,它的自由变量会在捕捉时被确定,这样即使脱离了捕捉时的上下文,它也能照常运行;
MDN对JavaScript闭包的解释:
一个函数和对其周围状态(lexical environment,词法环境)的引用捆绑在一起(或者说函数被引用包围),这样的组合就是闭包(closure);
大致总结就是: 一个函数如果访问到外层作用域的自由变量,这个函数就是一个闭包。
在代码中 function(...args) { ... } 这个函数就是闭包,访问到了外层作用域的fn, time, takes, timer 自由变量。
高阶函数
- 以函数为参数
- 以函数为返回值
两者满足一个就是高阶函数。
代码分析
consumer(add, 1000); 返回一个函数(闭包),并且将 add函数作为fn的值,1000作为time的值 绑定了起来,它赋值给了 consumerAdd函数。
for (let i = 0; i < 10; i++) { consumerAdd(ref, i); }
for循环执行十次 consumerAdd函数 ,在第一次执行中,ref, i 传给了 args,接着
fn也就是add函数传入 args,并且push到了 task数组里。
第一次执行的时候timer值为undefined,符合if条件,进入if语句里,然后遇到了setInterval异步操作,将里面的回调加入宏任务队列里,继续执行同步操作,即:循环完剩下的九次,push add函数到tasks数组。
执行完同步操作,开始执行宏任务队列里面的回调,隔一个 time ,取出 task数组里面的 add函数 执行,当数组为空的时候,timer 重新设置为 null。
可以去看一下打印的结果。
one more thing
tasks.push(fn.bind(this, ...args)); 这里的this值是什么? window