@[toc]
0 / 热热身
function fun(n, o) {
console.log(o);
return {
fun: function (m) {
return fun(m, n);
}
};
}
var c = fun(0).fun(1);
c.fun(2);
c.fun(3);
△ 答案是?
△ 图3.7_图解
1 / redux 中的compose函数
function compose(...funcs) {
if (funcs.length === 0) {
return arg => arg
}
if (funcs.length === 1) {
return funcs[0]
}
return funcs.reduce((a, b) => (...args) => a(b(...args)))
}
△ redux中的compose函数
我们普通写调用函数,但是可读性太差
const add1 = x => x + 1;
const mul3 = x => x * 3;
const div2 = x => x / 2;
div2(mul3(add1(add1(0)))); //=>3
△ 普通调用函数
那么,需要写一个可读性较高的组合函数:
const operate = compose(div2, mul3, add1, add1);
operate(0);
△ 调用compose函数
compose(div2, mul3, add1, add1)
传参的顺序与div2(mul3(add1(add1(0))))
调用函数的顺序关系
那么,我们上次写的reduceRight
从里面往外调用函数实现组合函数的调用
然而,redux使用的是reduce
按照输入参数的顺序调用的
咱就从EC/VO/AO 堆栈内存作用域的角度,一步一步分析就好
2 / 逐步分析
咱们就根据:执行上下文、作用域、作用域链、VO、AO这些一步步分析即可
// funcs=[div2,mul3, add1, add1] 函数集合
// return funcs.reduce((a, b) => (...args) => a(b(...args)))
return funcs.reduce((a, b) => {
let fn = (x) => {
return a(b(x));
};
return fn;
});
△ 分析reduce的写法
(1)compose()函数调用
【0】EC(C001) 假设这是compse() 执行形成的执行上下文
operate 是一个函数
那么 ,compose return 出去的是一个函数
let result = funcs.reduce((a,b)=>{
return function anonymous(x){
return a(b(x));
};
});
△ result 得到的是一个函数
result 接收到的结果是一个函数
此时,需要通过reduce每次调用callback形成 函数私有上下文
在每次的函数的私有上下文中,都会创建一个匿名函数
每个匿名函数所处的作用域是不同的
代码执行到:funcs.reduce(callback)
① reduce第一轮遍历
【1】 第一轮遍历 EC(CB1)私有执行上下文
AO(CB1) 变量对象
a=div2
b=mul3
anonymous=0xA001
作用域链:<EC(CB1), EC(C001)>
形参赋值:a=div2; b=mul3
变量提升:anonymous=0xA001
代码执行:
return function anonymous(x){
a(b(x));
}; //=====> 【return 0xA001】;
△ 第一轮循环返回的值
② reduce第一轮遍历
【2】第二轮遍历 EC(CB2) 私有执行上下文
AO(CB2) 变量对象
a=0xA001
b=add1
anonymous=0xA002
作用域链:<EC(CB2), EC(C001)>
形参赋值:a=0xA001; b=add1
变量提升:anonymous=0xA002
代码执行:
return function anonymous(x){
a(b(x));
}; //=> 【return 0xA002】;
△ 第二轮循环返回的值
③ reduce第三轮遍历
【3】第三轮遍历 EC(CB3)私有执行上下文
AO(CB3) 变量对象
a=0xA002
b=add1
anonymous=0xA003
作用域链:<EC(CB3), EC(C001)>
形参赋值:a=0xA003; b=add1
变量提升:anonymous=0xA003
代码执行:
return function anonymous(x){
a(b(x));
}; //=> 【return 0xA003】;
△ 第三轮循环返回的值
(4)reduce遍历结束后,赋值
三轮遍历结束后,把0xA003
赋值给operate
operate(0)
执行
③ 0xA003(0) 执行
【3】EC(0xA003)
AO(0xA003)
x=0
作用域链:<EC(0xA003),EC(CB3) >
形参赋值:x=0
代码执行:
a(b(x));
=> x 是自己的:x=0; a和b都是上级上下文的
=> a=0xA002
=> b=add1
==> 0xA002(add1(0))
=> add1(0) => x+1=1
=> add1(0) 就当它是最后结果了,为了最后看到的效果是一样的,就不写计算了
=> 0xA002() 调用
② 0xA002() 调用
【2】EC(0xA002)
AO(0xA002)
x = add1(0)
作用域链:<EC(0xA002),EC(CB2) >
形参赋值:x=add1(0)
代码执行:
a(b(x));
=> x 是自己的:x=add1(0);a和b都是上级上下文的
=> a=0xA001
=> b=add1
==> 0xA001(add1(add1(0)))
=> add1(add1(0))就当是计算后的结果了
=> 0xA001() 调用
① 0xA001() 调用
【1】EC(0xA001)
AO(0xA001)
x = add1(add1(0))
作用域链:<EC(0xA001),EC(CB1) >
形参赋值:x = add1(add1(0))
代码执行:
a(b(x));
=> x 是自己的:x=add1(add1(0)); a和b都是上级上下文的
=> a=div2
=> b=mul3
==> div2(mul3(add1(add1(0))))
即:div2(mul3(add1(add1(0))))
- end -
把你的心 我的心串一串
串一株幸运草 串一个同心圆
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。