javascript中bind繫結接收者與函式柯里化

liulun發表於2019-07-11

如果我要遍歷一個陣列,
我只要給forEach傳一個匿名函式即可,很簡單;

let arr = ['a', 'b', 'c'];
arr.forEach((item, index) => { 
    console.log(item);
    console.log(index);
})

如果我已經把匿名函式抽象出來,做成了一個公共的方法
(可能其他地方也會用的到)
那麼,這個遍歷會是這樣的;

let arr = ['a', 'b', 'c'];
let myFunc = (item, index) => {
    console.log(item);
    console.log(index);
}
arr.forEach(myFunc);

注意:只要把方法物件傳給forEach就可以嘍,引數什麼的,根本就不用關心;
如果這個方法在一個物件裡,那也沒什麼問題:

let obj = {
    add(param, index) {
        console.log(param);
        console.log(index)
    }
}
let arr = ['a', 'b', 'c'];
arr.forEach(obj.add);

但,如果涉及到物件的this,那就要出問題了:

let obj = {
    name: 'allen',
    add(param, index) {
        console.log(this.name);
        console.log(param);
        console.log(index)
    }
}
let arr = ['a', 'b', 'c'];
arr.forEach(obj.add);

輸出:

undefined
a
0
undefined
b
1
undefined
c
2

這是因為,add方法執行的時候,this物件指向的並不是obj,而是forEach的物件,forEach的物件是全域性物件golobal;
那想實現意圖怎麼辦呢?
最low的辦法就是給forEahc在套一個匿名函式

arr.forEach((item, index) => obj.add(item, index));

其次是給forEach方法再多傳遞一個引數:

arr.forEach(obj.add, obj);

這也不是什麼好主意,forEach你可以多傳一個obj進去,其他的類似forEach的方法,可不一定允許你多傳一個物件進去哦!
更好的辦法是:

arr.forEach(obj.add.bind(obj));

bind建立了一個新函式,這個函式跟obj.add一樣,唯一不同的是,新函式把this繫結了obj
也就是說把add方法繫結給了接收者obj;
現在假設我們的add方法,還需要另外一個引數title,而且這是第一個引數:

add(title, param, index) {
        console.log(title);
        console.log(param);
        console.log(index)
}

那該如何是好呢?
你可以直接在bind方法裡直接傳遞這個引數:

arr.forEach(obj.add.bind(obj, "mytitle"));

最終的程式碼是:

let obj = {
    add(title, param, index) {
        console.log(title);
        console.log(param);
        console.log(index)
    }
}
let arr = ['a', 'b', 'c'];
arr.forEach(obj.add.bind(obj, "mytitle"));

輸出結果是:

mytitle
a
0
mytitle
b
1
mytitle
c
2

將函式與其引數的一個子集繫結的技術稱為函式的柯里化;
比起顯式的封裝函式,這樣做更簡潔!
(一般人也更不容易看懂你的程式碼,哈哈哈!)





 

相關文章