함수 패턴

함수

함수는 일급 객체이다.
함수는 유효범위(scope)를 제공한다.

  • 런타임, 즉 프로그램 실행 중에 동적으로 생성할 수 있다.
  • 변수에 할당할 수 있고, 다름 변수에 참조를 복사할 수 있으며, 확장가능하고, 특별한 경우를 제외하면 삭제가 가능하다.
  • 다른변수의 인자로 전달할 수 있고, 다른 함수의 반환 값이 될 수 있다.
  • 자기 자신의 프로퍼티와 메서드를 가질 수 있다.

콜백 패턴

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
ver findNodes = function (callback) {
var i = 10000, nodes = [], found;
// 콜백 함수를 호출할 수 있는지 확인한다.
if ( typeof callback !== 'function' ) {
callback = false;
}
while (i) {
i -= 1;
/*
로직 구현
found = node;
*/
if ( callback ) {
callback(found)
}
nodes.push(found);
}
return nodes;
}
var hide = function (nodes) {
if ( Object.prototype.toString.call(nodes) === '[object Array]' ) {
var i = 0; max = nodes.length;
for ( ; i < max; i += 1 ) {
nodes[i].style.display = 'none';
}
} else {
node.style.display = 'none';
}
}
findNodes( function(node) {
node.style.display = 'none';
});

함수 반환하기

1
2
3
4
5
6
7
8
9
var setup = function() {
alert(1);
return function() {
alert(2);
}
}
var my = setup(); // alert(1);
my(); // alert(2);

setup()은 반환된 함수를 감싸고 있기 때문에 클로저를 생산한다.
클로저는 반환되는 함수에서는 접근할 수 있지만 코드 외부에서는 접근할 수 없기 때문에, 비공개 데이터 저장을 위해 사용 할 수있다.

ex) 카운터 예제

1
2
3
4
5
6
7
8
9
10
11
var setup = function() {
var count = 0;
return function() {
return count += 1;
}
}
var next = setup();
next(); // 1
next(); // 2
next(); // 3

자기 자신을 정의하는 함수

함수는 동적으로 정의할 수 있고 변수에 할당할 수 있다.
새로운 함수를 만들어 이미 다른 함수를 가지고 있는 변수에 할당한다면, 새로운 함수가 이전 함수를 덮어쓰게 된다.
포인터가 새로운 함수를 가리키도록 재사용하는 것이다.
본문 내에서도 이런일을 할 수 있는데, 이 경우 함수는 자기 자신을 새로운 구현으로 덮었고 재정의 한다.

1
2
3
4
5
6
var scareMe = function() {
alert('Boo!');
scareMe = function() {
alert("Double boo!");
};
}

이 패턴은 함수가 어떤 초기화 준비 작업을 단 한번만 수행할 경우에 유용하다.(lazy function pattern)
재 정의된 함수의 작업랼이 적기 때문에 애플리케이션 성능에 도움이 된다.
단점, 함수가 새로운 변수에 할당되면 예상과 달리 자기 자신을 정의하지 않는다.

즉시 실행 함수

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 객체프로퍼티 정의에 사용 (처음에 한번만 값을 계산해 정의하고 계속 사용.)
var o = {
message : (function() {
var who = 'me',
what = 'call';
return what + ' ' + who;
}()),
getMsg : function() {
return this.message;
}
}
// o.getMsg(); // call me
// o.message; // call me

초기화 시점의 분기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
var utils = {
addListener : null,
removeListener : null
}
// 구현
if ( typeof window.addEventListener === 'function' ) {
utils.addListener = function(el, type, fn) {
el.addEventListener(type, fn, false);
};
utils.removeListener = function(el, type, fn) {
el.addEventListener(type, fn, false);
};
} else if ( typeof document.attachEvent === 'function' ) {
// 구현...
} else {
utils.addListener = function(el, type, fn) {
el['on' + type] = fn;
}
utils.removeListener = function(el, type, fn) {
el['on' + type] = null;
}
}
...

함수 프로퍼티 - 메모이 제이션 패턴

1
2
3
4
5
6
7
8
9
10
var getId = (function() {
var cacheId = {};
return function(id) {
if( !cacheId[id] ) {
console.log(id);
cacheId[id] = document.getElementById(id);
}
return cacheId[id];
}
})();

설정 객체 패턴

함수의 매개변수를 객체로 받는다.
유지보수 용이, 다양한 요구사항에 대응.

1
2
3
4
5
6
7
8
9
var info = {
a : '1',
b : '2',
c : '3'
...
}
function add(info) {
}

커리

부분적인 함수 적용

1
2
3
4
5
6
7
8
9
var add = function(x, y) {
return x + y;
}
//모든 인자를 적용
add.apply(null, [4, 5]); // 9
// 인자를 부분 적으로 적용
var newadd = add.partialApply(null, [4]);
newadd.apply(null, [5]); // 9

자바스크립트는 기본적으로 이렇게 동작하지 않지만 굉장히 동적이기 때문에 이렇게 동작하도록 만들 수 있다.
커링 - 함수가 부분적인 적용을 이해하고 처리할 수 있도록 만드는 과정

커링(Curring)

수학자 하스켈 커리의 이름에서 따옴. (하스켈 언어와 같은 유래)
커링은 함수를 변형하는 과정이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 커링된 add()
// 부분적인 인자의 목록을 받는다.
function add(x, y) {
if ( typeof ㅛ === 'undefined' ) { // 부분적인 적용
return function(y) {
return x + y;
};
}
return x + y; // 전체 인자 적용
}
// 테슽
typeof add; // function
add(3)(4); // 7
// 새로운 함수를 만들어 저장
var add2000 = add(2000);
add2000(10); // 2010;

범용 커링 함수의 코드

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
function schonfinkelize(fn) {
console.log(arguments); // 전달받은 매개변수 객체
var slice = Array.prototype.slice,
stored_args = slice.call(arguments, 1);
console.log(stored_args); // 배욜 1 부터 끝
return function() {
console.log(arguments);
var new_args = slice.call(arguments),
aregs = stored_args.concat(new_args);
console.log(aregs);
return fn.apply(null, args);
}
}
// 일반함수
function add( x, y ) {
return x + y;
}
// 함수를 커링하여 새로운 함수를 얻는다.
var newadd = schonfinkelize(add, 5);
newadd(4); // 9
// 매개변수가 여러개이고, 커링이 여러단계 일때
function add(a, b, c, d, e, f) {
return a+ b+c+d+e+f;
}
// 여러개의 인자 사용;
schonfinkelize(add, 1, 2, 3)(5, 5); // 16
// 2단계 커링
var addOne = schonfinkelize(add, 1);
addOne(10, 10, 10, 10); // 41
var addSix = schonfinkelize(addOne, 2, 3); // addOne : 1단계에서 1값이 커링된 상태.
addSix(5, 5); // 16
  • 커링을 사용해야 하는 이유

요약

Share