안녕하세요. 송기석입니다.

 

저번 주에 온 눈으로 인해 길이 얼어 미끄러운 곳이 많습니다. 방심하다가 미끄러져 넘어지시면 큰일 납니다. 미끄러운 빙판길 조심하시고 올해 마무리를 잘 준비하시기를 기원합니다.

 

저번 주에 이어 문장에 대하여 강좌를 하려고 했습니다. 그렇게 쓴 강좌의 내용은 너무 뻔한 내용, 누구나 아는 내용, 어디서나 쉽게 찾을 수 있는 내용이 되었습니다. 쓰고 고치고 쓰고 고치고를 3번째 하고 이건 아니다는 생각이 들었습니다. 책이나 인터넷이나 그 외 다른 방법으로도 충분히 알 수 있는 내용을 쓰려고 한다면 지금부터 10년을 써도 끝나지 않을 것 같습니다.

 

오늘부터 시작하는 자바스크립트 강좌는 함수에 대한 것입니다. 이미 자바스크립트를 잡아라.-03 강좌에서 한번 했던 함수에 대한 내용은 함수 객체와 함수 리터럴에 대한 내용입니다. 그 부분은 넘어가고 아직 하지 않은 것을 하겠습니다.

호출


함수를 호출하면 현재 함수를 잠시 중단하고 제어를 매개변수와 함께 호출한 함수로 넘깁니다.

이 때 함수는 명시되어 있는 매개변수와 thisarguments라는 추가적인 매개 변수를 두 개를 받습니다.

this 매개변수는 객체지향 프로그램 관점에서 매우 중요하며, 이 매개변수의 값은 호출하는 패턴에 의해 결정됩니다. 자바스크립트에서 함수를 호출하는데 메소드 호출 패턴, 함수 호출 패턴, 생성자 호출 패턴, apply 호출 패턴의 4가지 패턴이 있습니다. 각각의 패턴에 따라 추가적인 매개변수를 다른게 초기화합니다.

함수를 호출하는 호출 연산자는 함수를 나타내는 표현식 뒤에 이어지는 한 쌍의 괄호인데 괄호 안에 표현식이 없을 수도 있고 하나 이상은 쉼표를 이용하여 나열합니다. 만약 인수가 더 많으면 초과하는 인수는 무시하고 반대로 부족한 인수는 undefined를 할당합니다.

this에 대하여


함수 호출에 대한 내용을 하다 보니 this매개변수가 나왔습니다. 우선 this매개변수에 대한 것을 정리하겠습니다. 자바스크립트는 다른 프로그래밍 언어에 사용되는 this와 다른 개념을 가지고 있습니다. 자바스크립트의 언어 사양에 메서드는 존재하지 않습니다. 객체의 프로퍼티에 함수를 설정한 것을 편의상 메서드라고 부를 뿐입니다.

this 참조


this 참조는 자바스크립트 코드의 어디서나 사용할 수 있는 읽기 전용 변수입니다. this 참조는 객체를 참조합니다. 참조하는 곳은 탑 레벨 코드와 함수 안에서 다릅니다. this 참조는 코드의 컨텍스에 따라 자동으로 참조할 객체가 변하는 특별한 것으로 생각할 수 있습니다.

 

함수 안의 this 참조에서 참조할 객체는 함수를 작성하는 방법이나 선언하는 방법으로 바뀌는 것이 아니라 함수를 호출하는 방법에 따라 바뀌는 것임에 주의해야 합니다. , 같은 함수라도 호출 방법이 다르면 this 참조는 다른 객체를 참조합니다.


자바스크립트에서는 크게 5가지 방식으로 this가 특정 값에 바인딩 될 수 있습니다.


The Global Scope

 

this;

this global 영역에서 이용할 경우, 그것은 단순히 global 객체를 가리킵니다.

 

Calling a Function

 

foo();

함수를 호출하는 경우 this는 역시 global 객체를 가리킵니다.

 

global영역에서 this를 사용하면 window 객체를 가리킨다면 foo(); 함수를 호출할 때 사용하면 foo(); 객체를 가리켜야 할 것 같지만 window 객체를 가리킵니다. 이유는 자바스크립트에서 사용하는 this는 항상 owner를 가리킵니다. ownerfunction을 실행시킨 객체를 가리키며, 다른 말로 function를 소유하고 있는 object라고 이해하면 됩니다. 결국 앞에서 나온 2가지 모두 window 객체를 가리킵니다.

 

Calling a Method

 

test.foo();

특정 객체의 메서드를 호출하는 경우, this는 해당 객체(여기서는 test 객체)를 가리킵니다.

 

Calling a Constructor

 

new foo();

new 다음에 이뤄지는 함수 호출은 생성자의 역할을 수행합니다.

이때 생성자 함수의 내부에서 this는 생성자에 의해 새로 생성되는 객체를 가리킵니다.

 

Explicit Setting of this

 

function foo(a, b, c) {}

 

var bar = {};

foo.apply(bar, [1, 2, 3]); // array will expand to the below

foo.call(bar, 1, 2, 3); // results in a = 1, b = 2, c = 3

 

function.prototype 객체의 call이나 apply 메서드를 사용하는 경우, 호출된 함수(예제에서는 foo 함수)의 내부에서 사용되는 this call이나 apply 메서드의 첫번째 인자로 명시적으로 설정됩니다.

 

그 결과 위 예제는 메서드 호출하는 경우의 this가 적용되지 않고, foo() 함수의 내부에서 this bar 객체를 가리킵니다. 이상이 5가지 this가 바인딩되는 방식입니다.




var obj = {
  x: 1,
  doit: function() { console.log('method is called. ' + this.x );}
};
obj.doit();		// "method is called. 1"
obj['doit']();		// "method is called. 1"
var fn = obj.doit;
fn();			// "method is called. undefined"
var x = 10;
fn();			// "method is called. 10"

var obj2 = { x:2, doit2:fn };
obj2.doit2();		// "method is called. 2"

var obj3 = {
  x:3,
  doit3: function() { console.log('dit3 is called. ' + this.x); this.doit4(); },
  doit4: function() { console.log('dit4 is called. ' + this.x); }
};
obj3.doit3();		// "dit3 is called. 3"  "dit4 is called. 3"

function f() { console.log(this.x); }
var obj4 = { x:4 };
f.apply(obj4);		// 4
f.call(obj4);		// 4
var obj5 = {
  x:5,
  doit5: function() { console.log('dit5 is called. ' + this.x); }
};
var obj6 = { x:6 };
obj5.doit5.apply(obj6);	// "dit5 is called. 6"
function f1(a, b) { console.log('this.x = ' + this.x + ', a = ' + a + ', b = ' + b);}
f1.apply({x:4}, [1, 2]);	// "this.x = 4, a = 1, b = 2"
f1.call({x:4}, 1, 2);	// "this.x = 4, a = 1, b = 2"

  1. "method is called. 1" 결과는 객체obj가 리시버 객체이고 doit이 메서드입니다.
  2. "method is called. undefined" 결과는 fn()이 전역함수이므로 리시버 객체가 window객체가 됩니다. 현재 window객체에 x값이 없으므로 undefined가 나옵니다. 
  3. "method is called. 10" 결과는 x에 10을 넣어 전역번수 값을 설정하여 fn()을 호출하였을 때 전역변수 x의 값이 10이 나옵니다. 4. "method is called.
  4. " 결과는 fn()를 실행하는 것은 결국 obj2이므로 obj2객체가 리시버 객체가 됩니다. 
  5. "dit3 is called. 3" "dit4 is called. 3" 결과는 dit3와 dit4는 메소드가 되고 obj3가 리시버 객체가 됩니다. 
  6. 4 결과는 apply와 call메소드를 이용해서 호출한 함수 안의 this참조를 지정한 임의의 객체를 참조하는데 쓸 수 있습니다. 
  7. "dit5 is called. 6" 결과는 apply를 사용하여 obj6을 호출합니다. 6번과 같은 경우로 앞에 obj5.doit5부분이 있지만 결국 obj6이 리시버 객체가 됩니다. 
  8. "this.x = 4, a = 1, b = 2" 결과는 각각 두 번째 인자의 배열요소와 두 번째 인자부터 함수 f의 인자가 됩니다.
이번 강좌를 통해 this에 대하여 저만 알아 볼 수 있는 글을 썼습니다. 이미 … 강좌를 쓰는데 인내력을 다 사용해서 수정할 힘이 없습니다. 전체 내용 중 코드를 직접 실행해 보시고 this참조를 하였을 때 어떤 객체를 가리키는지를 중점으로 보면 되겠습니다.