221011 TIL | 자바스크립트 코딩 기법과 핵심 패턴_#4 함수

개요

  • 자바스크립트의 함수는 다음과 같은 특징을 가지는 객체이다.
    1. 런타임, 즉 프로그램 실행 중에 동적으로 생성할 수 있다.
    2. 변수에 할당할 수 있고 다른 변수에 참조를 복사할 수 있으며, 확장 가능하고 몇몇 특별한 경우를 제외하면 삭제할 수 있다.
    3. 다른 함수의 인자로 전달할 수 있고, 다른 함수의 반환 값이 될 수 있다.
    4. 자기 자신의 프로퍼티와 메서드를 가질 수 있다.
  • 함수가 객체라는 사실은 다음과 같은 new Function() 생성자의 동작을 보면 명백해진다.
// 안티패턴
// 데모의 목적으로만 사용한다
var add = new Function('a, b', 'return a + b'); 
add(l, 2); // 3을 반환한다
  • 자바스크립트의 함수는 유효 범위를 제공한다.
    • 자바스크립트에서는 중괄호 지역 유효범위가 없다.
      • 블록이 유효범위를 만들지 않으며, 함수 유효범위가 있을 뿐이다.
      • if 조건문이나 for문, while 문 내에서 var로 정의해도 if나 for문의 지역변수가 되지 않는다.
      • 해당 블럭을 감싸는 함수가 있을 때만 지역변수가 된다.
    • 전역 변수를 최소화하는 것이 좋기 때문에 변수의 유효범위를 관리하기 위해서 함수는 매우 중요하다.

용어 정리

기명 함수 표현식(named function expression)

var add = function add(a, b) {
	return a + b;
};

무명 함수 표현식(unnamed function expression)

  • 함수 표현식(function expression), 익명 함수(anonymous function)라는 말로도 쓰인다.
// 함수 표현식 (또는 익명 함수)
var add = function (a, b) { 
	return a + b;
};

함수 선언문

  • 함수 표현식의 결과를 변수에 할당하지 않을 경우이다. (콜백 패턴이라고 한다)
  • 세미콜론이 붙는지 여부에 따라 문법적인 차이점이 있다.
    • 선언문은 없어도 되지만 표현식은 있어야 함.
function foo() {
	// 함수 본문
}

선언문 vs 표현식

// 함수 표현식을 callMe 함수의 인자로 전달한다. 
callMe(functior) () {
	// 이 함수는 무명 함수(익명 함수) 표현식이다.
});

// 기명함수표현식을 callMe 함수의 인자로 전달한다. 
callMe(function me() {
	// 이 함수는 "me”라는 기명 함수 표현식이다. 
});

// 함수 표현식을 객체의 프로퍼티로 저장한다.
var myobject = {
	say: function () {
		// 이 함수는 함수 표현식이다. 
	}
};
  • 함수 선언문은 전역 유효범위나 다른 함수의 본문 내부, 즉 프로그램 코드에서만 쓸 수 있다.
    • 변수나 프로퍼티에 할당할 수 없고 함수 호출 시 인자로 함수를 넘길 때도 사용할 수 없다.

함수 선언문보다 표현식을 선호하는 이유는 표현식을 사용하면 함수가 다른 객체들과 마찬가지로 객체의 일종이며, 어떤 특별한 언어 구성요소가 아니라는 사실이 드러나기 때문이다.

함수 호이스팅

  • 함수 선언문과 기명 함수 표현식은 호이스팅(hoisting) 동작에서 차이점을 보인다.
  • 모든 변수는 함수 본문의 어느 부분에서 선언(declaration)되더라도 내부적으로 함수 맨 윗부분으로 끌어올려(hoist)진다.
  • 함수 또한 결국 변수에 할당되는 객체이기 때문에 동일한 방식이 적용된다.
  • 하지만 함수 선언문을 사용하면 변수 선언 뿐만아니라 함수 정의(definition) 자체도 호이스팅 되기 때문에 자칫 오류를 만들어내기 쉽다.
// 안티패턴 : 설명을 위해 사용한다.

// 전역 함수
function foo() { 
	alert('global foo');
}
function bar() { 
	alert('global bar');
}

function hoistMe() {
	console.log(typeof foo); // "function"
	console.log(typeof bar); // ⭐⭐⭐ "undefined" ⭐⭐⭐
	foo(); // "local foo"
	bar(); // TypeError: bar is not a function
	// 함수 선언문:
	// 변수 ‘foo’와 정의된 함수 모두 호이스팅된다. 
	function foo() {
		alert('local foo'); 
	}
	// 함수 표현식:
	// 변수 ‘bar'는 호이스팅 되지만 정의된 함수는 호이스팅되지 않는다. 
	var bar = function () {
		alert('local bar’); 
	};
} 
hoistMe();
  • hostMe() 함수 내에서 foo와 bar를 정의하면 실제 변수를 정의한 위치와 상관없이 끌어올려져 전역 변수인 foo와 bar를 덮어쓴다.
  • 그런데 지역변수 foo()는 나중에 정의되어도 상단으로 호이스팅되어 정상 동작하는 방면, bar()의 정의는 호이스팅 되지 않고 선언문만 호이스팅 된다.

콜백 패턴

  • a라는 함수의 인자에 b가 전달되면 a는 어느 시점에 b를 실행할 것이다.
  • 이때 b를 콜백 함수 또는 콜백이라고 부른다.
function a (callback) {
	// ...
}
function b () {
	// ...
}
a(b);
  • 콜백 함수는 괄호를 붙이지 않고 전달한다.
    • 괄호를 붙이면 함수가 바로 실행되기 때문이다.

콜백 예제

  • 예제는 콜백 없이 시작하여 리팩터링을 한다.
  • 복잡한 작업을 수행 후 그 결과로 대용량 데이터셋을 반환하는 범용 함수가 있다고 하자.
  • DOM 트리를 탐색해 필요한 엘리먼트의 배열을 반환한다.
var findNodes = function () { 
	var i = 100000, // 긴 루프
	nodes = [], // 결과를 저장할 배열
	found; // 노드 탐색 결과 
	while (i) {
		i -= 1;
		// 이 부분에 복잡한 로직이 들어간다.
		nodes.push(found);
	}
	return nodes;
};
  • findNodes는 범용으로 쓸 수 있도록 실제 엘리먼트에는 어떤 작업도 하지 않고 단지 DOM 노드의 배열을 반환하기만 하도록 유지한다.
  • 노드를 수정하는 로직은 다른 함수를 만든다. hide()
var hide = function (nodes) {
	var i = 0, max = nodes.length; 
	for (; i < max; i += 1) {
		nodes[i].style.display = "none"; 
	}
};

// 함수를 실행한다.
hide(findNodes());
  • findNodes()에서 반환된 노드의 배열에 대해 hide()가 다시 루프를 돌아야 하기 때문에 비효율적이다.
  • findNodes()에서 노드를 선택하고 바로 숨긴다면 재차 루프를 돌지 않아 효율적이겠지만, findNodes()는 범용적인 함수이기 때문에 탐색과 수정 로직이 결합될 경우 범용 함수의 의미가 퇴색된다…

    → 이럴 때 콜백 패턴을 사용할 수 있다.

  • 노드를 숨기는 로직의 실행을 콜백 함수에 위임하고, 이 함수를 findNodes()에 전달한다.
// findNodes()가 콜백을 받도록 리팩터링한다. 
var findNodes = function (callback) {
	var i = 100000, nodes = [],
	found;
	// 콜백 함수를 호출할 수 있는지확인한다 .
	if (typeof callback !== "function") { 
		callback = false;
	}
	while (i) { 
		i -= 1;
		// 이곳에 복잡한 로직을 구현한다.
		// 여기서콜백을실행한다.
		if (callback) { 
			callback(found);
		}
		nodes.push(found);
	}
	return nodes;
};
  • findNodes()에는 콜백 함수가 추가되었는지 확인하고 있으면 실행하는 작업만 추가되기 때문에 직관적이다.
// 콜백 함수
var hide = function (node) {
	node.style.display = "none";
};

// 노드를 찾아서 바로 숨긴다.
findNodes(hides);
  • hide()처럼 이미 존재하는 함수를 콜백 함수로 쓸 수도 있지만 findNodes() 함수를 호출할 때 익명 함수를 생성하여 쓸 수도 있다.
// 익명 함수를 콜백으로 전달한다.
findNodes(function (node) { 
	node.style.display = "block";
});

콜백과 유효범위

  • callback(parameter); 방식으로 실행 시 대부분 훌륭하게 작동하지만,
    • 콜백이 일회성의 익명 함수나 전역 함수가 아니고 객체의 메서드인 경우,
    • this를 사용하면 예기치 않게 동작할 수 있다.
var myapp = {};
myapp.color = "green"; 
myapp.paint = function (node) {
	node.style.color = this.color;
};

var findNodes = function (callback) {
	// ...
	if (typeof callback === function") { 
		callback(found);
	}
// ... };
  • findNodes(myapp.paint)를 호출하면 this.color가 정의되지 않아 예상대로 동작하지 않는다.
  • findNodes()는 전역 함수이기 때문에 객체 this는 전역 객체를 참조한다.
  • findNodes()가 dom이라는 객체의 메서드라면, 콜백 내부의 this는 예상과는 달리 myapp이 아닌 dom을 참조하게 된다.
  • 이 문제를 해결하기 위해서는 콜백 함수와 함께 콜백이 속해있는 객체를 전달하면 된다.
findNodes(myapp.paint, myapp);
  • 전달받은 객체를 바인딩하도록 findNodes() 또한 수정한다.
var findNodes = function (callback, callback_obj) { 
	//...
	if (typeof callback === "function") { 
		callback.call(callback_obj, found);
	}
	// ... 
};
  • 콜백으로 사용할 메서드와 객체를 전달할 때 메서드를 문자열로 전달할 수도 있다.
  • 명령을 이렇게 바꿀 수 있다. findNodes(myapp.paint, myapp);**findNodes("paint", myapp);**
  • 두 가지 방법에 모두 대응하는 함수를 다음과 같이 만들 수 있다.
var findNodes = function (callback, callbackobj) {
	if (typeof callback === "string") { 
		callback = callback obj[callback];
	}
	//...
	if (typeof callback === "function") {
		callback.call(callback_obj, found); }
	// ... 
};

비동기 이벤트 리스너

  • 페이지의 엘레먼트에 이벤트 리스너를 붙이는 것도 실제로는 이벤트가 발생했을 때 호출될 콜백 함수의 포인터를 전달하는 것이다.
  • 다음 에제는 document의 click 이벤트 리스너로 console.log() 콜백함수를 전달하는 예제이다.
document.addEventListener("click", console.log, false);
  • 대부분 클라이언트측 브라우저 프로그래밍은 이벤트 구동(event-driven)방식이다.
  • 페이지의 로딩이 끝나면 load 이벤트를 발생시킨다.
  • 사용자는 페이지에 click, kepress, mouseover, mousemove와 같은 다양한 이벤트를 발생시킨다.
  • 자바스크립트가 이벤트 구동형 프로그래밍에 특히 적합한 이유는 프로그램이 비동기적으로, 달리 말하면 무작위로 동작할 수 있게 하는 콜백 패턴 덕분이다.

타임아웃

  • 또 다른 콜백 패턴의 실전 예제는 브라우저 window 객체에 의해 제공되는 타임아웃 메서드들인 setTimeout()과 setInterval()이다.
  • 이 메서드들도 콜백 함수를 받아 실행시킨다.
var thePlotThickens = function () { 
	console.log('500ms later...');
};
setTimeout(thePlotThickens, 500);

라이브러리에서의 콜백

  • 라이브러리 메서드는 핵심 기능에 집중하고 콜백의 형태로 연결고리(hook)을 제공하라.
  • 콜백 함수를 활용하면 쉽게 라이브러리 메서드를 만들고 확장하고 가다듬을 수 있다.

함수 반환하기

  • 예제의 setup()은 초기화 작업 수행 후 실행 가능한 함수를 반환 값으로 하는 함수이다.
var setup = function () { 
	alert(1);
	return function () { 
		alert(2);
	}; 
};
// setup 함수를 사용
var my = setup(); // alert으로 1이 출력된다.
my(); // alert으로 2가 출력된다.
  • setup()은 반환된 함수를 감싸고 있기 때문에 클로저를 생성한다.
  • 클로저는 반환되는 함수에서는 접근할 수 있지만, 코드 외부에서는 접근할 수 없기 때문에 비공개 데이터 저장을 위해 사용할 수 있다.

자기 자신을 정의하는 함수

  • 새로운 함수를 만들어 이미 다른 함수를 가지고 있는 변수에 할당한다면, 새로운 함수가 이전 함수를 덮어쓰게 된다.
  • 어떤 면에서는 이전의 함수 포인터가 새로운 함수를 가지도록 재사용하는 것이다.
  • 함수 본문에서 이런 일을 하는 예제를 확인 해보자.
var scareMe = function () { 
	alert("Boo!");
	scareMe = function () { 
		alert("Double boo!");
	}; 
};
// 자기 자신을 정의하는 함수를 사용
scareMe(); // Boo! 
scareMe(); // Double boo!
  • 함수가 초기화 준비 작업을 단 한번만 수행할 경우에 유용하다.
  • 이 패턴의 단점은 자기 자신을 재정의한 이후에는 이전에 원본 함수에 추가했던 프로퍼티들을 모두 찾을 수 없게 된다는 점이다.
  • 또한 함수가 다른 이름으로 사용된다면, 예를 들어 다른 변수에 할당되거나 객체의 메서드로써 사용되면 재정의된 부분이 아니라 원본 함수의 본문이 실행된다.
  • scareMe() 함수를 다음과 같이 일급 객체로 사용하는 예제를 확인 해보자.

    1. 새로운 프로퍼티가 추가된다.

    2. 함수 객체가 새로운 변수에 할당된다.

    3. 함수는 메서드로써도 사용된다.

      // 1. 새로운 프로퍼티를 추가한다. 
      scareMe.property = "properly";
      // 2. 다른 이름으로 할당한다. 
      var prank = scareMe;
      // 3. 메서드로 사용한다. 
      var spooky = {
      	boo: scareMe 
      };
        
      // 새로운 이름으로 호출한다.
      prank(); // "Boo!"
      prank(); // "Boo!" 
      console.log(prank.property); // "properly"
        
      // 메서드로 호출한다.
      spooky.boo(); // "Boo!"
      spooky.boo(); // "Boo!" 
      console.log(spooky.boo.property); // "properly"
        
      // 자기 자신을 재정의한 함수를 사용한다.
      scareMe; // Double boo!
      scareMe(); // Double boo! 
      console.log(scareMe.property); // undefined
    

즉시 실행 함수

  • 함수가 선언되자마자 실행되도록 하는 문법
(function () { 
	alert('watch out!');
})();
  • 이 패턴은 초기화 코드에 유효범위 샌드박스(sandbox)를 제공한다는 점에서 유용하다.

즉시 실행 함수의 매개변수

  • 즉시 실행함수에 인자를 전달할 수도 있다.
// 출력결과:
// I met Joe Black on Fri Aug 13 2010 23:26:59 GMT-0800 (PST) 
(function (who, when) {
	console.log("I met " + who +  on " + when); 
}("Joe Black", new Date()));
  • 즉시 실행 함수는 객체 프로퍼티를 정의할 때도 사용할 수 있다.
    • 어떤 객체의 프로퍼티가 객체의 생명주기동안 값이 변하지 않고,
    • 처음 값을 정의할 때 적절한 계산을 위한 필요하다고 가정했을 때
    • 작업을 즉시 실행 함수로 감싼 후 반환 값을 프로퍼티 값으로 할당하면 된다.

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

  • 함수에 프로퍼티를 추가하여 결과(반환 값)를 캐시하면 다음 호출 시점에 복잡한 연산을 반복하지 않을 수 있다.
  • 이런 활용 방법을 메모이제이션 패턴이라고 한다.
var myFunc = function (param) { 
	if (!myFunc.cache[param]) {
		var result = {};
		// ... 비용이 많이 드는 수행 ...
		myFunc.cache[pa ram] = result;
	}
	return myFunc.cache[param];
};
// 캐시 저장공간
myFunc.cache = {};
  • 예시는 param이라는 단 하나의 매개 변수를 받는다고 가정하고 매개변수는 문자열과 같은 원시 데이터 타입이라고 가정한다.
  • 객체 인자를 JSON 문자열로 직렬화하고 문자열을 cache 객체에 키로 사용할 수 있다.
var myFunc = function () {
var cachekey = JSON.stringify( 
	Array.prototype.slice.call(arguments)), result;
	if (!myFunc.cache[cachekey]) { 
		result = {};
		// ... 비용이 많이 드는 수행 ...
		myFunc.cache[cachekey] = result;
	}
	return myFunc.cachefcachekey];
};
// 캐시 저장공간
myFunc.cache = {};

커리(Cury)

  • 커링(currying)과 부분적인 함수 적용에 대해 알아보자

함수 적용

  • 순수한 함수형 프로그래밍 언어에서 함수는 불려지거나 호출된다고 표현하기 보다 적용(apply)된다고 표현한다.
  • 자바스크립트에서도 Function.prototype.apply() 를 사용하면 함수를 적용할 수 있다.
// 함수를 호출한다.
sayHi(); // "Hello"
sayHi('world'); // "Hello, world!"
// 함수를 적용(apply)한다.
sayHi.apply(null, ["hello"]); // "Hello, hello!"

  • 함수 적용과 함수 호출은 같은 결과를 보여준다.
  • apply()는 두 개의 매개변수를 받는데,
    • 첫 번째는 이 함수 내에 this와 바인딩할 객체이고,
    • 두 번째는 배열 또는 인자(arguments)로 함수 내부에서 배열과 비슷한 형태의 arguments 객체로 사용하게 된다.
  • 첫번째 매개변수가 null이면 this는 전역객체를 가리킨다.
    • 함수를 특정 객체의 메서드가 아닌, 일반적인 함수로 호출할 때와 같다.
  • 함수가 객체의 메서드일 때는 null을 전달하지 않는다.
var alien = {
	sayHi: function (who) {
		return"Hello"+(who?","+who: "")+"!"; 
	}
};

alien.sayHi('world'); // "Hello, world!"
sayHi.apply(alien, ["humans"]); // "Hello, humans!"
  • 함수 호출이라는 것은 사실 함수 적용을 가리키는 문법 설탕(syntatic sugar)이다.
  • apply()와 비슷한 call()이라는 메서드 또한 마찬가지이다.
  • call() 메서드는 전달하는 매개변수가 배열이 아닌 하나의 요소일 뿐이다.
// 배열을 만들지 않는 두 번째 방법이 더 효과적이다.
sayHi.apply(alien, ["humans"]); // "Hello, humans!" 
sayHi.call(alien, "humans"); // "Hello, humans!"

부분적인 적용

  • 함수의 호출이 실제로는 인자의 묶음을 함수에 적용하는 것임을 알게 되었다.
  • 인자 전부가 아니라 일부 인자만 전달하려면 어떻게 할까?
  • 수학 함수를 직접 계산할 때 쓰는 방법과 비슷하다.
// 설명을 위한 목적으로 사용되었다. 
// 자바스크립트에서는 유효하지 않다.
// 이런 함수가 있고
function add(x, y) { 
	return x + y;
}

// 인자들을 알고있다.
add(5, 4);

// 1단계 -- 하나의 인자를 대체한다. 
function add(5, y) {
	return 5 + y; 
}

// 2단계 -- 나머지 인자를 대체한다. 
function add(5, 4) {
	return 5 + 4; 
}
  • 부분적인 적용을 실행하면 결과가 나오는 대신 또다른 함수가 나온다.

  • 다음은 부분적인 적용을 실행한 결과를 함수로 만들고, 이 함수에 다른 인자 값을 적용하여 호출할 수 있는 partialApply() 메서드의 사용법을 알아보자.

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

// 새로운 함수에 인자를 적용
newadd.apply(null, [4]); // 9
  • 사실 partialApply() 메서드는 존재하지 않고, 자바스크립트의 함수 또한 이렇게 작동하지 않는다.
  • 하지만 자바스크립트는 굉장히 동적이기 때문에 이렇게 동작하도록 만들 수 있다.
  • 함수가 부분적인 적용을 이해하고 처리할 수 있도록 만드는 과정을 커링(Curring)이라고 한다.

커링(Curring)

  • 수학자 하스켈 커리(Haskell Curry)로 유래되었다.
    • 하스켈 프로그래밍 언어도 그의 이름에서 따온 것이다.
  • 다른 함수형 언어에서는 커링 기능이 언어 자체에 내장되어 있어 모든 함수가 기본적으로 커링된다.
  • 자바스크립트에서는 add() 함수를 수정하여 부분 적용을 처리하는 커링 함수로 만들 수 있다.
// 커링된 add()
// 부분적인 인자의 목록을 받는다.
function add(x, y) {
	var oldx = x, oldy = y;
	if (typeof oldy === "undefined") { // 부분적인 적용
		return function (newy) { 
			return oldx + newy;
		}; 
}
	// 전체 인자를 적용
	return x + y; 
}

// 테스트
typeof add(5); // "function" 
add(3)(4); // 7

// 새로운 함수를 만들어 저장
var add2000 = add(2000); 
add2000(10); // 2010
  • 예제는 이해를 돕기 위해 풀어서 쓴 식이며, 조금 더 간략화 할 수 있다.
  • oldx와 oldy를 없애는 방법
    • 원래의 x는 암묵적으로 클로저에 저장되어 있고
    • 이전 예제에서 newy라는 새로운 변수를 만들었던 것과 다르게 지역 변수 y를 재사용한다.
// 커링된 add
// 부분적인 인자의 목록을 받는다.
function add(x, y) {
	if (typeof y === "undefined") { // 부분적인 적용
		return function (y) { 
			return x + y;
		}; 
	}
	// 전체 인자를 적용
	return x + y; 
}
  • 어떤 함수라도 부분적인 매개변수를 받는 함수로 변형할 수 있을까?
  • 범용 커링 함수 코드이다.
function schonfinkelize(fn) {
	var slice = Array.prototype.slice,
		stored_args = slice.call(arguments, 1);
	return function () {
			var new_args = slice.call(arguments),
			args = stored_args.concat(new_args); 
		return fn.apply(null, args);
	}; 
}
  • arguments가 실제로는 배열이 아니기 때문에 코드가 조금 복잡해진다.
  • Array.prototype으로부터 slice() 메서드를 빌려오면 arguments를 배열로 바꿔 사용하기 편리하게 만들 수 있다.
  • 예제의 매커니즘은 다음과 같다.
    1. 지역변수 slice에 slice() 메서드에 대한 참조를 저장한다.
    2. stored_args에 인자를 저장한다.
    3. 이 때 첫번째 인자는 커링될 함수이기 때문에 떼어낸다.
    4. 새로운 함수를 반환한다.
    5. 반환된 새로운 함수는 호출되었을 때 클로저를 통해 비공개로 저장해둔 stored_args와 slice 참조에 접근할 수 있다.
    6. stored_args와 새로운 인자 new_args를 합친다.
    7. 클로저에 저장되어 있는 원래의 함수 fn에 적용한다.

커링 예제

// 일반 함수
function add(x, y) { 
	return x + y;
}

// 함수를 커링하여 새로운 함수를 얻는다
var newadd = schonfinkelize(add, 5); 
newadd(4); // 9

// 반환되는 새로운 함수를 바로 호출할 수도 있다.
schonfinkelize(add, 6)(7); // 13

// 혹은 인자가 여러개일 때...

// 일반 함수
function add(a, b, c, d, e) { 
	return a+b+c+d+e;
}
// 여러 개의 인자를 사용할 수도 있다.
schonfinkelize(add, 1, 2, 3)(5, 5); // 16

커링을 사용해야 할 경우

  • 어떤 함수를 호출할 때 매개변수가 항상 비슷하다면 커링의 적합한 후보이다.
  • 매개변수 일부를 적용하여 새로운 함수를 동적으로 생성하면,
  • 이런 함수는 반복되는 매개변수를 내부적으로 저장하여 매번 인자를 전달하지 않아도 원본 함수가 기대하는 전체 목록을 미리 채워놓을 것이다

.

요약

함수의 중요한 특징

  1. 함수는 일급 객체다. 값으로 전달될 수 있고, 프로퍼티와 메서드를 확장할 수 있다.
  2. 함수는 지역 유효범위를 제공한다. 다른 중괄호 묶음은 그렇지 않다. 로컬 변수의 선언은 로컬 유효범위의 맨 윗부분으로 호이스팅 된다.

함수의 여러 가지 패턴

  • API 패턴 : 함수에 더 좋고 깔끔한 인터페이스를 제공할 수 있게 도와준다.
    • 콜백 패턴 : 함수를 인자로 전달한다.
    • 설정 객체 : 함수에 많은 수의 매개변수를 전달할 때 통제를 벗어나지 않도록 해준다.
    • 함수 반환 : 함수의 반환 값이 또다시 함수일 수 있다.
    • 커링 : 원본 함수와 매개변수 일부를 물려받는 새로운 함수를 생성한다.
  • 초기화 패턴 : 전역 네임스페이스를 어지럽히지 않고 임시 변수를 사용해 좀더 깨끗하고 구조화된 방법으로 수행한다.
    • 즉시 실행 함수
    • 즉시 객체 초기화
    • 초기화 시점의 분기
  • 성능 패턴 : 코드의 실행 속도를 높인다.
    • 메모이제이션 패턴
    • 자기선언 함수