Higher Order Functions in JavaScript_1 - Lee-hyuna/33-js-concepts-kr GitHub Wiki
λ²μ : http://www.zsoltnagy.eu/higher-order-functions-in-javascript/
μ΄ κΈ°μ¬μμλ κ³ μ°¨ ν¨μμ λν΄ νμ΅ν©λλ€. ν¨μν νλ‘κ·Έλλ°μ μ€μν μ΄μμ κ³ μ°¨ ν¨μμ λλ€. λλΆλΆ functional μ€νμΌλ‘ νλ‘κ·Έλ¨μ μμ±νλ €λ©΄ κ³ μ°¨ ν¨μμ κΈ°λ³Έ μ¬νμ μμ§ν΄μΌν©λλ€.
λ¨Όμ , κ³ μ°¨ ν¨μμ κ°λ¨ν μ μλ₯Ό λ°°μλλ€. μ΄λ―Έ μ¬μ©μ€μΈ κ³ κΈ ν¨μλ₯Ό 보μ¬μ€μΌλ‘μ¨ μ μλ₯Ό κΈ°μ΅ν κ²μ λλ€. κ³ μ°¨ ν¨μ μμ λ₯Ό ꡬννμ¬ μ΄ κΈμ λ§μΉκ² μ΅λλ€.
κ³ μ°¨ ν¨μλ ν¨μ μΈμλ₯Ό λ°κ±°λ ν¨μλ₯Ό λ°ννλ ν¨μμ λλ€.
λλ μ΄ μ μμμ λͺ¨μλ μλ―Έκ° μλλλ€.
μ΄μ μΉμ μμ JavaScript ν¨μλ κ°μ΄λΌλ κ²μ λ°°μ μ΅λλ€. λ°λΌμ ν¨μλ λ€λ₯Έ ν¨μλ‘ μ λ¬ λ μ μμΌλ©° ν¨μμ λ°ν κ°μΌ μλ μμ΅λλ€.
μ΄κ²μ κ³ μ°¨ ν¨μλ₯Ό μ΄ν΄νλ λ° νμν λͺ¨λ μ΄λ‘ μ λλ€. κ³ μ°¨ ν¨μλΌλ μ΄λ¦μ μ²μμλ 무μμ 보μ΄μ§λ§ μ€μ λ‘λ μ무κ²λ λλ ΅μ§ μμ΅λλ€. ν¨μλ₯Ό μΈμλ‘ μ λ¬νκ±°λ λ°ν κ°μΌλ‘ λ°ννλ©΄λ©λλ€.
νΉν JavaScript λ―Έλ μ½μ€λ₯Ό κ²ͺμ κ²½μ° μ΄λ―Έ λ§μ κ³ μ°¨ ν¨μλ₯Ό μκ³ μμ μ μμ΅λλ€.
setTimeout( () => console.log('done'), 1000 );
κ³ μ°¨ ν¨μμ μ’μ μλ setTimeout μ
λλ€. setTimeout
μ 첫 λ²μ§Έ μΈμλ ν¨μμ΄λ―λ‘ setTimeout
μ κ³ μ°¨ ν¨μμ
λλ€.
document.querySelector( '.js-submit' )
.addEventListener( 'click', submitCallback );
DOM λ Έλμ μ΄λ²€νΈλ₯Ό μΆκ° ν λ μ΄λ²€νΈλ₯Ό λ±λ‘νλ ν¨μλ κ³ μ°¨ ν¨μμ λλ€.
setTimeout
κ³Ό addEventListener
λ λͺ¨λ ν¨μ μΈμλ₯Ό κ°μ§κ³ μκΈ° λλ¬Έμ κ³ μ°¨ ν¨μμ
λλ€. μ΄μ ν¨μλ₯Ό λ°ννλ μμ λ₯Ό 보μ.
컨ν
μ€νΈ λ°μΈλ©μ λ°μΈλ© λ this
κ°μ΄μλ ν¨μλ₯Ό λ°νν©λλ€. λ°λΌμ bind
λ κ³ μ°¨ ν¨μμ
λλ€.
const area = function() {
return this.width * this.height;
};
const boundArea = area.bind({ width: 2, height: 3 });
boundArea();
κΈ°μ μ μΌλ‘ bind
λ νλ‘ν νμ
μ²΄μΈ μμμ ν΅ν 'μμ'κ°μ²΄μ λ°©λ²μ
λλ€. bind
λ λ
립ν ν¨μμ΄κ³ area
λ μΈμ μΈ νμμΌλ‘ λ©μλ νΈμΆμ νμ λ€μ μμ±ν μ μμ΅λλ€.
const bind = function( f, ...args ) {
return f.bind( ...args );
}
const boundArea = bind( area, { width: 2, height: 3 } );
λ€μ μμ±ν νμλ bind
κ° ν¨μ μΈμλ₯Ό νμ© ν λΏλ§ μλλΌ ν¨μλ λ°ννλ€λ κ²μ λΆλͺ
ν μ μ μμ΅λλ€.
μ¬μ©λ²μ 보μ¬μ£ΌκΈ° μν΄ κ³ μ°¨ ν¨μλ₯Ό μ§μ μμ±νκ³ μΆμ μλ μμ΅λλ€.
centsλ₯Ό λνλ΄λ μ μ κ°μ ννλ‘ νμννλ μμ μ΄ μλ€κ³ κ°μ νμμμ€. μμ²μλ ν΅ν κΈ°νΈ μ§μ λ° μμ κ΅¬λΆ κΈ°νΈμ κ°μ μΌλΆ μ¬μ©μ μ μκ° ν¬ν¨λ©λλ€.
ν νλ¦Ώ 리ν°λ΄ λ°ν κ°μ΄ μ΅μνμ§ μμ κ²½μ° λ¬Έμμ΄ λ° ν νλ¦Ώ 리ν°λ΄μ λν λ΄ κΈ°μ¬strings and template literals.λ₯Ό μ½μΌμμμ€.
const formatCurrency = function(
currencySymbol,
decimalSeparator ) {
return function( value ) {
const wholePart = Math.trunc( value / 100 );
let fractionalPart = value % 100;
if ( fractionalPart < 10 ) {
fractionalPart = '0' + fractionalPart;
}
return `${currencySymbol}${wholePart}${decimalSeparator}${fractionalPart}`;
}
}
> getLabel = formatCurrency( '$', '.' );
> getLabel( 1999 )
"$19.99"
> getLabel( 2499 )
"$24.99"
formatCurrency
λ κ³ μ ν΅ν κΈ°νΈμ μμμ κ΅¬λΆ κΈ°νΈκ° μλ ν¨μλ₯Ό λ°νν©λλ€.
ν¬λ§·ν°μ κ°μ μ λ¬ν λ€μ μ 체 λΆλΆκ³Ό μμ λΆλΆμ μΆμΆνμ¬ μ΄ κ°μ νμμ μ§μ ν©λλ€. ES6 μν νμ₯ trunc μ μ¬μ©νμ¬ κ²°κ³Όλ₯Ό μλ¦ λλ€.
μ΄ ν¨μμ λ°ν κ°μ ν΅ν κΈ°νΈ, μ 체 λΆλΆ, μμ κ΅¬λΆ κΈ°νΈ λ° μμ λΆλΆμ μ°κ²°νλ ν νλ¦Ώ 리ν°λ΄λ‘ ꡬμ±λ©λλ€.
ν΅ν κΈ°νΈμ μμ κ΅¬λΆ κΈ°νΈλ λ°ν λ ν¨μμ μ λ¬λμ§ μμΌλ©° κ³ μ λ κ°μ λλ€.
μ°λ¦¬λ μ μ κ°μ getLabel ν¨μμ μ λ¬ν μ μκ³ ν¬λ§· λ ννμ λ€μ μ»μ΅λλ€.
λ°λΌμformatCurrency
κ³ μ°¨ ν¨μλ μ¬μ© κ°λ₯ν ν¬λ§·ν° ν¨μλ₯Ό λ¦¬ν΄ νμ΅λλ€.
μΌλΆ κ³ μ°¨ ν¨μλ JavaScriptμμ λ°°μ΄μ μ²λ¦¬νλ λ° μ μ©ν©λλ€. μ€μ λ‘ λλΆλΆμ κΈ°λ₯μ μ€νμΌλ‘ μ½λλ₯Ό μμ±ν λ μ’ μ’ λ£¨ν λμ μ΄λ¬ν ν¨μλ₯Ό μ¬μ©ν©λλ€. μ΄λ¬ν κΈ°λ₯μ λ€μκ³Ό κ°μ΅λλ€.
-
map
, -
reduce
, -
filter
.
λ΄κ° μforEach
λ°©λ²μ μΈκΈνμ§ μμμ΅λκΉ? κ²°κ΅, μ°λ¦¬λ 루νμ λν΄ μ΄μΌκΈ°νκ³ μμ΅λλ€.
forEach
μ λ¬Έμ μ μ ν¨μν νλ‘κ·Έλλ°μμ μμ ν μΈλͺ¨μλ ν¨μλΌλ κ²μ
λλ€. μμνκ² κΈ°λ₯μ μΈ μ€νμΌλ‘ μ½λλ₯Ό μμ±ν λ forEach
λ₯Ό μ¬μ©νλ κ²μ μλ―Έκ° μμ΅λλ€. κ°λ¨ν μλ₯Ό λ΄
μλ€.
const values = [1, 2, 3, 3, 5];
let sum = 0;
values.forEach( v => { sum += v; } );
console.log( sum );
forEach
ν¬νΌλ κ°
μ λ°λ³΅νκ³ λ°°μ΄μ κ° κ°μ λν 첫 λ²μ§Έ μΈμλ₯Ό νΈμΆν©λλ€. μ΄ forEach
νΈμΆμ μ£Όμ ν¨κ³Όλ 'μ μλμ§ μμ'μ΄ λ°νλλ€λ κ²μ
λλ€. μ΄ κ΄μ μμ ν¨μ λ³Έλ¬Έμ 무μμ΄ μλμ§λ μ€μνμ§ μμ΅λλ€. ν¨μ λ³Έλ¬Έ sum + = v
λ₯Ό μ€ννλ©΄ side-effect κ° μμ±λμ΄ forEach
λμ°λ―Έμ λ²μλ₯Ό λ²μ΄λ 컨ν
μ€νΈλ₯Ό μμ ν©λλ€.
μμ κΈ°λ₯ νλ‘κ·Έλλ°μ side-effect free μ
λλ€. λ°°μ΄μ forEach
λμ°λ―Έλ μ¬μ© κ°λ₯ν κ°μ λ°ννμ§ μμ΅λλ€. λ°λΌμ forEach
λ₯Ό μ¬μ©νλ μ μΌν μ΄μ λ forEach
μ μ½λ°± λ΄μμ λΆμμ©μ μμ‘΄νλ κ²μ
λλ€.
κΈ°μ μΈν°λ·°μμ, ν보μλ€μ΄ ν¨μν νλ‘κ·Έλλ°μ μ¬μ©νκ² λ€κ³ μ μΈ ν λ μ’ μ’ λΉν©μ€λ¬μ 보μ΄λ―λ‘
for
루ν λμ μforEach
λμ°λ―Έλ₯Ό μ¬μ©ν©λλ€. μ΄ ν¨μ μ λ€μ΄ κ°μ§ λ§μμμ€.
λ°°μ΄μ μ‘°μνλ λ λμ κΈ°λ₯μ΄ μμ΅λλ€. reduce
λ‘ κ°μ κ²°κ³Όλ₯Ό μ»μ μ μμ΅λλ€ :
const values = [1, 2, 3, 3, 5];
const sum = values.reduce( (accumulator, v) => accumulator + v, 0 );
console.log( sum ); // 14
Reduceλ ν¨μ μΈμκ°μλ κ³ μ°¨ ν¨μμ λλ€. μ΄ ν¨μ μΈμλ λ°°μ΄μ κ° μμμμ μ€νλ©λλ€. λ°°μ΄μμ λμ°κΈ° λ³μμ νλμ κ°μ κ°μ Έμ΅λλ€. μ΄ ν¨μ μΈμμ λ°ν κ°μ λμ°κΈ°μ μλ‘μ΄ κ°μ λλ€. μ΄ μλ‘μ΄ κ°μ λ€μ μμμ μνλ λ€μ νΈμΆμμ μ¬μ©λ©λλ€.
κ° λ°λ³΅μμ λμ°κΈ° λ³μμ μνμ λ€μ λ°°μ΄ κ°μ μΈμνκ² μ΅λλ€.
const values = [1, 2, 3, 3, 5];
const sum = values.reduce( (accumulator, v) => {
const result = accumulator + v;
console.log( `accumulator, v, result: ${ accumulator }, ${ v }, ${ result }` );
return result;
}, 0 );
λ€μ κ°μ΄ μ½μμ μΈμλ©λλ€.
accumulator, v, result: 0, 1, 1
accumulator, v, result: 1, 2, 3
accumulator, v, result: 3, 3, 6
accumulator, v, result: 6, 3, 9
accumulator, v, result: 9, 5, 14
κ·Έκ²μ΄ λΉμ μ΄ κ°μμ λν΄ μμμΌ ν μ λΆμ λλ€. 곧 μ΄λμ ν μ μμΌλ©° μ€μ λ‘ μ΄λμ μ¬μ©ν μ μμ΅λλ€.
λ€μ ν¨μλmap
μ
λλ€. Mapμ λ°°μ΄μ κ° μμλ₯Ό κ°μ Έ μμ μ½λ°± ν¨μλ₯Ό μ¬μ©νμ¬ λ³ννκ³ λ³ν λ κ°μ λ°°μ΄μ λ°ννλ κ³ μ°¨ ν¨μμ
λλ€.
μλ₯Ό λ€μ΄, λ€μ μμ μ¬μ©νλ©΄ λ€λ₯Έ 2μ κ±°λ μ κ³±μ μ»μ μ μμ΅λλ€.
> [0, 1, 2, 3, 4].map( v => 2 ** v );
[1, 2, 4, 8, 16]
**
λ ES2016
μ λμ
λ μ§μ μ°μ°μμ
λλ€. 2 ** v
λ₯Ό β2μ κ±°λ μ κ³±βμΌλ‘ μ½μ΅λλ€.
μ΄μ 2
μ μ²μ 50μ νμ λ§λ€μ΄ λ΄
μλ€. μμΌλ‘ 51 κ°μ μμλ‘ κ΅¬μ±λ λ°°μ΄μ λ§λ€κ³ μΆμ§ μλ€κ³ κ°μ νλ©΄ null
μμλ‘ λ°°μ΄μ λ§λ€ μ μμ΅λλ€.
new Array( 51 ).fill( null )
map
ν¨μμ μ½λ°±μ λ°°μ΄μ νμ¬ μμμ μΈλ±μ€ μΈ λ λ²μ§Έ μΈμλ₯Ό νμ© ν μ μμ΅λλ€.
> new Array( 51 ).fill( null ).map( (item, index) => index )
(51) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
ν λ¨κ³ λ§ λ¨μμ΅λλ€. index
λ₯Ό λ°ννλ λμ 2 ** μΈλ±μ€
λ₯Ό λ°νν΄μΌν©λλ€.
> new Array( 51 ).fill( null ).map( (item, index) => 2 ** index )
(51) [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624]
μ μ΄λ μ²μ 20 κ° κ°μ μκ³ μλ μννΈμ¨μ΄ κ°λ°μ μΉκ΅¬κ° μμ΅λλ€. κ·Έλλμ΄ μ«μλ₯Ό μ°λ κ²λ³΄λ€ λΉ λ₯΄κΈ° λλ¬Έμmap
μ μ¬μ©νμ¬μ΄ λ°°μ΄μ λ§λλλ€.
μΈ λ²μ§Έ κ³ μ°¨μ λ°°μ΄ ν¨μλ 'νν°'μ λλ€. μ°λ¦¬λ λ°°μ΄μμ μΌλΆ μμλ₯Ό λ²λ¦¬κ³ λλ¨Έμ§ μμ λ§ μ μ§νλ λ°°μ΄μ λ°ννλ €κ³ ν μ μμ΅λλ€.
μλ₯Ό λ€μ΄ λ°°μ΄μμ λͺ¨λ μμ μμλ₯Ό λ²λ¦¬κ³ μΆλ€κ³ κ°μ ν΄λ³΄μμμ€.
> [-1, 5, 2, -4, -2, 2].filter( v => v >= 0);
[5, 2, 2]
array.filter (f)
λ κ·Έ μμλ€μ νν°λ‘ μ μ§νμ¬f (element)
κ° μ°Έλ κ°μ λ°νν©λλ€.
truthy κ°μ΄ 무μμΈμ§ λͺ¨λ₯΄λ©΄ this article λ€μμ νμΈνμΈμ
λ°ν λ°°μ΄μ 맀ννκ³ νν°λ§ν©λλ€.
μ΄λ μ΄μμ 맡, μΆμ λ° νν°κ° μλν©λλ€.
λ°λΌμ μΌλ ¨μ 맡 λ° νν° νΈμΆμ μλ‘ μ°κ²°ν μ μμΌλ©° λμ μ½μ μ€ μλ μμ΅λλ€.
μλ₯Ό λ€μ΄, λ¬Έμμ΄ λ°°μ΄μ΄ μκ³ a
λ‘ μμνλ κ°μ₯ κΈ΄ λ¬Έμμ΄μ κΈΈμ΄λ₯Ό μ°Ύλ λ° κ΄μ¬μ΄ μλ€κ³ κ°μ νμμμ€.
λ€μ λ¨κ³λ₯Ό μ¬μ©νμ¬ μ루μ μ μ°Ύμ μ μμ΅λλ€.
- 'a'λ‘ μμνμ§ μλ μμλ₯Ό νν°λ§νμμμ€.
- μμλ₯Ό κΈΈμ΄μ 맡ννμμμ€.
- μ΄ κΈΈμ΄μ κ°λ€μ μ΅λκ°μΌλ‘ νμ ν΄λΌ.
const words = ['ab', 'abc', 'bcde'];
words
.filter( w => w.startsWith( a ) )
.map( w => w.length )
.reduce( (acc, v) => Math.max( acc, v ), 0 );
μ°Έκ³ : κΈ°μ μ μΌλ‘λ μ΅λ λ°°μ΄μ μ¬μ©νκΈ° μν΄ reduceλ₯Ό μ¬μ©ν νμκ° μμ΅λλ€. μ°λ¦¬λ λ°©κΈ μΈ μμμμ΅λλ€ :
Math.max( ...wordLengths );
λ λ§μ μ€λΉκ° λμ ¨λ€λ©΄μ΄ λΈλ‘κ·Έ κ²μλ¬Όμμ 맡 κ°μ νν° μ°μ΅μ μ½μ΄λ³΄μμμ€. SQL λ¬Έμ map-reduce-filter νΈμΆλ‘ λ³νν΄μΌν©λλ€.
λΉλμ€ λ²μ μ μ νΈνλ κ²½μ° μ¬κΈ°μμ νμΈνμμμ€.
<iframe width="560" height="315" src="https://www.youtube.com/embed/uhQptpmffhY" frameborder="0" allow="autoplay; encrypted-media" allowfullscreen=""></iframe>κ³ μ°¨ ν¨μλ ν¨μ μΈμλ₯Ό λ°κ±°λ ν¨μλ₯Ό λ°ννλ ν¨μμ λλ€.
λΉμ μ μλ§λ κ·Έκ²λ€μ λν΄ μκ°νμ§ μκ³ λ§μ κ³ μ°¨ ν¨μλ₯Ό μ΄λ―Έ μ¬μ©νκ³ μμ κ²μ
λλ€. setTimeout
, μ΄λ²€νΈ 리μ€λ μ½λ°± λλbind
ν¨μλ₯Ό μκ°ν΄λ³΄μμμ€.
map
,reduce
λ°filter
μ κ°μ μΌλΆ κ³ μ°¨ ν¨μλ λ°°μ΄μλ³΄λ€ μ½κ² ββμ²λ¦¬νλ λ° λμμ΄λ©λλ€.
ν¨μν νλ‘κ·Έλλ°μ λν μμΈν λ΄μ©μ λ³΄λ €λ©΄ Safari Books Online : Functional Dive into Functional JavaScriptμμ 5 μ±κΈ μ½μ€λ₯Ό νμΈνμμμ€. /). μ΄ κ³Όμ μ κΈ°λ₯μ νλ‘κ·Έλλ°μ λν νλ₯ν μ λ¬Έ μλ£λ‘ κ°λ ₯ν μΆμ² ν μ μμ΅λλ€.
λλ‘λ Packt μ¬μ΄νΈμμλ λ§μ κ²μ μ»μ μ μμ΅λλ€. Packtμ Deep Dive into Functional JavaScript νμ΄μ§μ λλ€. κ·Έλ¬λ Packtμ νλ‘λͺ¨μ μ λ΄κ° κ΄λ¦¬ ν μ ββμμΌλ―λ‘ $ 120- $ 140 κ°κ²©νκ° 10 λ¬λ¬λ‘ νλ½νμκΈ°λ₯Ό μ μ μμ΅λλ€.
λ§μ§λ§μΌλ‘ JavaScript λ―Έλ μ½μ€μ κ°μ νλ©΄ λ λ§μ μ 보λ₯Ό μ»μ μ μμ΅λλ€.
- arrow functions,
- destructuring,
- functions with variable number of arguments,
- the ES6 class syntax,
- the spread operator and rest parameters,
- destructuring.