본문 바로가기

Web/JavaScript

함수형 자바스크립트 3. 반복자(_each)와 내부다형성

_filter와 _map 구현에서의 중복

1. for문으로 loop를 도는 부분

1
for ( var i = 0; i < list.length; i++ )
cs

2. i번째 요소를 찾는 부분

1
2
3
if ( predi(list[i]) ) {
    new_list.push( list[i] );
}
cs


_each 구현

1
2
3
4
5
6
7
8
9
/* 리스트를 순회 */
/* for 문을 돌면서 하는일을 완전히 iter에게 위임 */
function _each( list, iter ) {
    for ( var i = 0; i < list.length; i++ ) { 
        iter( list[i] );        
    }
 
    return list;
}
cs


_each 함수를 이용해서 _filter와 _map 함수의 중복을 제거할 수 있다.

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
51
52
53
54
55
56
57
58
var users = [
    { id: 1name"ID", age: 36 }, 
    { id: 2name"BJ", age: 32 },
    { id: 3name"JM", age: 32 },
    { id: 4name"PJ", age: 27 },
    { id: 5name"HA", age: 25 },
    { id: 6name"JE", age: 26 },
    { id: 7name"JI", age: 31 },
    { id: 8name"MP", age: 23 }
];
 
function _filter( list, predi ) {
    var new_list = [];
    _each( list, function(val) {
        if ( predi(val) ) {
            new_list.push( val );
        }
    });
    return new_list;
}
 
function _map( list, mapper ) {
    var new_list = [];
    _each( list, function(val) {
        new_list.push( mapper(val) );
    });
    return new_list;
}
 
function _each( list, iter ) {
    for ( var i = 0; i < list.length; i++ ) { 
        iter( list[i] );        
    }
 
    return list;
}
 
console.log(    
    _map(
         _filter( users, function(user) {
            return user.age >= 30;
        }),
        function(user) {
            return user.name;
        }
    )
);
 
console.log(    
    _map(
         _filter( users, function(user) {
            return user.age < 30;
        }),
        function(user) {
            return user.age;
        }
    )
);
cs


메소드와 함수

1
2
3
4
5
6
7
8
9
10
11
12
/* 자바스크립트에 이미 있는 메소드 */
console.log(
    [1234].map(function(val) {
        return val * 2;
    })
);
 
console.log(
    [1234].filter(function(val) {
        return val % 2;
    })
);
cs

자바스크립트에는 Array 객체에 map, filter 메소드가 정의되어있다.

이런 객체의 메소드는 객체 상태에 따라 결과가 달라지기 때문에 순수 함수라고 할 수 없다.


메소드는 객체지향 프로그래밍에서 사용한다.

어떤 클래스에 정의되어 있기 때문에, 해당 클래스의 인스턴스에서만 사용할 수 있다.


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
/* $('div') -> Array가 아닌 Array like 객체이다 */
console.log(document.querySelectorAll('*'));
 
/* Array라면 map 메소드가 있어야 하는데 없음
console.log(
    document.querySelectorAll('*').map(function(node) {
        return node.nodeName;
    })
); */
 
console.log(
    document.querySelectorAll('*').map(function(node) {
        return node.nodeName;
    })
); */
 
/* 배열이 아니어도, length가 있고, (key, value)면 Array Like 객체이며 _map, _filter와 같은 함수에 사용할 수 있다 */
console.log(
    _map(
        document.querySelectorAll('*'),
        function(node) {
            return node.nodeName;
        }
    )
);
cs

Jquery() 나 document.querySelectorAll() 메소드를 호출하면 Array는 아니지만 Array와 비슷한 Array Like 객체가 반환된다.

Array Like 객체는 Array와 마찬 가지로 length를 멤버변수로 갖고 있으며 (k, v)의 형태로 데이터를 저장한다.

이러한 Array Like 객체의 인스턴스로 map이나 filter를 호출하면 정의되어있지 않기 때문에 에러가 난다.


1
2
3
4
5
6
7
8
console.log(
    _map(
        document.querySelectorAll('*'),
        function(node) {
            return node.nodeName;
        }
    )
);    
cs

메소드는 해당하는 클래스에 준비되어 있지 않으면 사용할 수 없기 때문에 다형성을 다루기가 어렵다.

이러한 메소드가 아닌 이전에 만든 _filter, _map 함수를 호출하면 Array Like 객체에서도 같은 작업이 가능하다.

함수를 먼저 만들고, 함수에 맞는 데이터를 구성하면서 프로그래밍하기 때문에, 높은 다형성을 갖게 되어 유연하고 실용적인 형태가 된다.


내부 다형성

1
2
3
4
5
console.log(
    _map([1234], functino(v) {
        return v + 10;
    })
);
cs

응용 함수의 두번째 인자로 들어가는 익명 함수(보조 함수)를 주로 콜백 함수라고 부르는 경향이 있다.

하지만, 이 보조 함수가 어떠한 역할을 하는지에 따라 다양한 이름으로 부르는게 중요하다.

콜백함수

어떠한 작업을 다 수행한 뒤 마지막에 다시 돌려주는 것을 뜻하는 함수

Predicate

조건절

Iterator

반복자

Mapper

무언가와 무언가의 사이를 매핑하는 함수