上次我們提到如何新增 instance method,讓我們先來複習一下
添加 instance method JavaScript 是 prototype based 的程式語言,比起其他程式語言特別的地方是,他們具有 function 這個型別 我們會稱呼他為原型物件,但是我們還是會直接稱它為物件
copyright by Giamir
每個原型物件也會有自己的原型而形成原型鏈,最後直到接到 null 為止
copyright by pjchender
當我們要在特定的原型添加屬性或是函數的話,只需要直接呼叫 prototype 來實作即可:
1 2 3 4 5 6 7 8 9 function Example ( ) { } Example.prototype.value = 123 ; Example.prototype.myFunction = function ( ) { console .log("hey myFunction" ); };
如此一來,基於原型實現的物件就可以擁有這些原型方法可以用了:
1 2 3 4 const a = new Example();console .log(a.value);a.myFunction();
實作 forEach 讓我們先來看看 forEach 是如何使用
1 2 3 4 5 const array = [1 , 2 , 3 ];array.forEach((value ) => { console .log(value); });
關於 Currying
copyright by
Ranando King
把接受多個參數的 function 變成只接受單一一個參數的 function,我們就稱它為 Currying function。 對一開始接觸他的人,就像是在天書一樣,甚至不知道為什麼要這樣設計。 在討論 Currying 之前,讓我們先來看看他究竟解決了什麼問題吧
在數學中,把(A, B, C) -> D 變成 A -> B -> C -> D 他所做的事情就是把 function 的接口單純化 而 JavaScript 又剛好可以使用閉包搭配遞迴的操作來做到這樣 functional programming 的操作 所以也就被一些人拿來當作簡潔程式碼的攥寫方式了
例如我要實現 add 要加總:
1 2 3 4 5 const add = (a, b, c ) => { return a + b + c; }; add(1 , 2 , 3 );
我今天希望把它從(A, B, C) -> D 變成 A -> B -> C -> D
那我就可以這樣做:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const add = (a ) => { console .log("a: " , a); return (b ) => { return (c ) => { return a + b + c; }; }; }; add(1 )(2 )(3 ); const add1 = add(1 );const add3 = add(1 )(2 );const add3 = add1(2 );const add6 = add(1 )(2 )(3 );const add6 = add1(2 )(3 );const add6 = add3(3 );
這個時候你就會發現,他擁有遞迴的概念,只是遞迴的對象變成了 function 所以我們可以這樣寫:
1 2 3 4 5 6 7 8 9 10 11 12 const add = (num ) => { return (nextNum ) => { if (nextNum) { return add(num + nextNum); } else { return num; } }; }; const test = add();console .log(test(1 , 2 , 3 ));
根據那神奇的數學公式呢,我們可以可以把它變成以下的 function:
1 2 3 4 5 6 const curry = (func ) => (...args ) => args.length < func.length ? (...moreArgs ) => curry(func)(...args, ...moreArgs) : func(...args);
看起來很可怕,不過我們來 step by step
我們知道根據公式,currying 是只有一個參數 所以可以先寫成這樣: A -> (…)
1 2 3 const curry = (func ) => { };
再來我們把剩下那一大坨參數丟到裡面的 function 記住喔,因為是串聯起來的,所以直接 return 它
1 2 3 4 5 6 const curry = (func ) => { const innerCurrying = (...args ) => { }; return innerCurrying; };
再來我們要判斷剩下的那一坨參數的數量為多少
1 2 3 4 5 6 7 8 9 10 const curry = (func ) => { const innerCurrying = (...args ) => { if (args.length > func.length) { return (...moreArgs ) => curry(func)(...args, ...moreArgs); } else { return func(...args); } }; return innerCurrying; };
Currying 實際應用 今天我希望使用 map 讓 array 所有的值都 double,可以這樣設計:
1 2 3 4 5 6 7 const array = [1 , 2 , 3 , 4 , 5 ];const doubleNumber = (num ) => num * 2 ;const result = array.map(doubleNumber);console .log("result: " , result);
但是之後突然多了其他需求:
1 2 3 4 const array = [1 , 2 , 3 , 4 , 5 ];const doubleNumber = (num ) => num * 2 ;const tripleNumber = (num ) => num * 3 ;
哎呀,多了一個結構類似的 method 了,我們來簡化他吧
1 2 3 4 5 6 7 const array = [1 , 2 , 3 , 4 , 5 ];const doubleNumber = (num ) => num * 2 ;const result = (n ) => array.map(doubleNumber);console .log("result: " , result(2 ));