從EC/VO/AO堆棧內存和做用域角度分析compose函數 | 跟着redux大佬學編程思想

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

@[toc]javascript

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);

△ 答案是?java

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

△ 圖3.7_圖解redux

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函數函數

咱們普通寫調用函數,可是可讀性太差spa

const add1 = x => x + 1;
const mul3 = x => x * 3;
const div2 = x => x / 2;
div2(mul3(add1(add1(0)))); //=>3

△ 普通調用函數code

那麼,須要寫一個可讀性較高的組合函數:對象

const operate = compose(div2, mul3, add1, add1);
operate(0);

△ 調用compose函數blog

compose(div2, mul3, add1, add1)傳參的順序與div2(mul3(add1(add1(0)))) 調用函數的順序關係ip

那麼,咱們上次寫的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】;

△ 第三輪循環返回的值

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

(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))))

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

- end -

公衆號:朝霞的光影筆記 ID:zhaoxiajingjing

把你的心 個人心串一串

串一株幸運草 串一個同心圓

相關文章
相關標籤/搜索