지금까지 알아본 클로저의 개념을 잘 이해하고 따라오셨나요? 그렇다면 이제 이 클로저라는 특별한 함수를 어떻게 사용하는지, 그 예제를 함께 확인해 볼 차례입니다. 우선, 아래와 같은 예제 코드가 있다고 해봅시다.
function HelloFunc() {
this.greeting = "hello_World!";
}
HelloFunc.prototype.call = function(func) {
func ? func(this.greeting) : this.func(this.greeting);
};
var userFunc = function(greeting) {
console.log(greeting);
};
var ojbHello = new HelloFunc();
ojbHello.func = userFunc;
ojbHello.call();
위 예제에서, 생성자 함수 HelloFunc( )가 선언되고 prototype에서의 정의를 통해 call( ) 함수에 인자로 전달된 함수를 호출하거나 또는 HelloFunc 객체에 사용자가 직접 선언한 func를 호출하는 형태로 선언되었습니다. 물론 이 func를 실행할 때는 인자로 HelloFunc를 통해 생성된 객체가 가진 greeting이라는 프로퍼티를 인자로 사용합니다.
이 함수는 정상적으로 "hello_World!"가 출력되는 것을 확인할 수 있습니다. 그런데, 이 함수를 자세히 살펴보면, call( )에서 정의된 내용을 보면 this.greeting이라는 인자 1개 만을 받아서 사용자가 정의한 함수를 실행합니다. 그러므로, 사용자가 정의한 함수(userFunc)의 파라미터도 단 한 개 만을 정의하고 있습니다. 이제 사용자가 원하는 인자를 추가로 넣어서 실행하는 방법이 있을지 살펴보도록 하겠습니다.
function HelloFunc() {
this.greeting = "hello_World!";
}
HelloFunc.prototype.call = function(func) {
func ? func(this.greeting) : this.func(this.greeting);
};
var ojbHello = new HelloFunc();
function saySomething(obj, methodName, name) {
return (function(greeting) {
return obj[methodName](greeting, name);
});
}
function newObj(obj, name) {
obj.func = saySomething(this, "who", name);
return obj;
}
newObj.prototype.who = function(greeting, name) {
console.log(greeting + " " + (name || "everyone") );
};
var obj1 = new newObj(ojbHello, "zzoon");
obj1.call();
식이 다소 복잡해졌습니다. 위의 예제 코드에서 일부 라인의 실행문을 제거하고 작성한 내용입니다. 이번에는 다소 내용이 복잡합니다. 우선, 결론만 말하면 위의 saySomething에서 반환되는 function(greeting) { ... } 라인이 클로저로서 작동합니다.
newObj는 예외적이지만 생성자 함수로 사용했습니다. 그래서 obj.func에 할당되는 saySomething( )함수에서 첫 번째 인자로 this가 사용되는데, 생성자 함수이기 때문에(new 키워드 사용) 여기서 this는 newObj 객체를 통해 생성되는 객체를 의미하게 됩니다. 단, 실제로 리턴은 obj를 리턴하게 되므로 주의해야 합니다. 그래서 saySomething 함수의 첫 번째 인자는 newObj { } 객체가 됩니다. 만일 일반적인 생성자 함수 사용 패턴에서처럼, [this.프로퍼티 = 매개변수]의 형태였다면 특정 속성을 가진 newObj 객체가 바인딩되겠지만, 여기서는 단순히 newObj{ } 객체가 할당된다고 이해하시면 됩니다. 결과적으로 saySomething( ) 함수에서는 newObj.who(greeting, name)을 실행하는 함수가 리턴되는 클로저 함수가 되는 것이죠. 이 부분은 기존 생성자 함수 기본 패턴과 약간 차이가 있기 때문에, 여러 번 반복해서 읽어 이해하시기 바랍니다.
잠깐, 헷갈릴 수 있는 부분이 있어서 다시 한 번 짚고 넘어갈 코드가 있습니다.
function plus(x, y) {
console.log(x + y);
}
var newT = function(a){
return plus(a, "ON!");
}
newT(1);
// 출력 : 1ON!
어떤 함수의 실행 결과를 리턴하는 경우, 위와 같이 함수 실행문 자체를 리턴한다고 가정하면, 즉시 결과 값을 얻을 수 있습니다. 위의 saySomething에서도 비슷한 코드가 등장하니, 주의해 주세요.
추가로, newObj에서 파라미터 인자값으로 사용되는 this에 많은 혼란이 있을 수 있습니다. 생성자 함수 형태로 사용할 때, this.name = name....과 같은 형태로 this가 생성 객체와 바인딩 되는 경우로 학습했을 것이기 때문에 혼선이 올 수 있습니다.
아래와 같이, 생성자 함수 형태로 실행되는 경우에 this가 생성 객체와 바인딩 되지 않는 경우를 참고해주세요. 그러면 this가 newObj 자체가 바인딩 되는 것을 이해할 수 있을 것입니다.
function testObj(){
console.dir(this);
}
var test = new testObj();
function Person(name){
console.dir(this);
this.name = name;
console.dir(this);
}
var personTest = new Person('JOHN');
// 출력
// testObj {}
// Person {}
// Person { name: 'JOHN' }
'Programming > Javascript' 카테고리의 다른 글
12. Javascript 클로저(Closure)(2) - 클로저의 활용 3 (0) | 2022.11.25 |
---|---|
12. Javascript 클로저(Closure)(2) - 클로저의 활용 2 (0) | 2022.11.23 |
12. Javascript 클로저(Closure)(1) - 클로저의 정의 3 (0) | 2022.11.19 |
12. Javascript 클로저(Closure)(1) - 클로저의 정의 2 (0) | 2022.11.18 |
12. Javascript 클로저(Closure)(1) - 클로저의 정의 1 (2) | 2022.11.14 |