當它越難拿到,你就會越想留住。
Jay Mark Mateo Balmes
本篇不是討論Partial Applications本身,而是他在控制流程中的優勢!
正如昨天說提到的,某些邏輯需要被抽離成函式時,是包含條件的,或是參數是依情況而定的,此時基於closure的partial applications就是使用的最佳時機。舉例來說,我們有個functionpower
,他會取三個數字作為引數,並且由左至右做冪次。這個例子複雜之處就是,該函式也容許並非三個引數都有值。
直觀的寫法可能會長這樣:
// 未使用partial applications
// 可能會被討厭的寫法
function power(n1, n2, n3) {
if (n1 && !n2) {
return n1;
}
if (n1 && !n3) {
return n1 ** n2;
}
if (n1 && n2 && n3) {
return (n1 ** n2) ** n3;
}
}
console.log(power(2)); //2
console.log(power(2, 3)); //8
console.log(power(2, 3, 3)); //512
在這個寫法中,當參數變多,很快就會令人困惑。因為我們需要對輸入做校驗,因此需要非常多的if
陳述句。順帶一提,我們可以仔細看這些if
陳述句,看看這個函式做了哪些前提假設。
為了解決上述問題,我們可以用partial application重構power
:
// 使用partial applications
// 比較不會被討厭的寫法
function power(n1) {
return (n2) => {
return n2 ? power(n1 ** n2) : n1;
}
}
console.log(power(2)()); //2
console.log(power(2)(3)()); //8
console.log(power(2)(3)(3)()); //512
我們可以看到這個例子中,代碼簡潔了許多。不僅如此,我們可以做無限次的冪次。事實上,或許有人看到這個例子的代碼初期會比較困惑,因為這個例子中牽涉到遞迴的使用。接下來,我們來看一個更輕量級在React中的例子。
我們這邊非常的簡單地考量React中雙向綁定表單欄中的輸入值。
const App = () => {
const [username, setUsername] = useState('');
const setInput = (setter) => (event) => {
setter(event.currentTarget.value);
}
return(
<form>
<input
value={username}
onChange={setInput(setUsername)}
/>
</form>
);
}
在這裡,我們不用多個function calls,我們使用partial application(這裡同時是currying)把setter function最為引數,並返回hanlder給onChange prop.