자바스크립트 this에 대해 알아보자 개발자로서의 Berry



  이번에는 조금 복잡한 이야기를 해볼까요?


  자바스크립트 this 키워드에 대한 설명은 함수 파트에서 함께 진행하려고 하였습니다만 this를 통해 곤란해 하는 분들이 많아 앞당겨 진행하겠습니다. 이번에 드리는 설명을 올바르게 이해하기 위해서는 자바스크립트의 함수, 그리고 객체에 대한 정확한 이해가 밑받침 되어야합니다.


  자바스크립트는 가볍게 쓰는 경향이 있기 때문에 메커니즘을 착각하기도 쉽습니다. 자바스크립트에서 this의 본질은 여타언어 C++, Java등과 다르지 않습니다. this는 메서드를 호출한 호출객체를 가르킵니다. 이를테면


  // 자바스크립트의 객체 생성방법 중 하나
  var people = new Object();
  people.name = "thinkberry";
  people.displayName = function() { alert(this.name); }
  
  peolpe.displayName();
  

  위의 코드를 실행하게 되면 thinkberry가 뜨게 되죠. this는 곧 메서드를 호출한 객체 즉 자신을 가리키게 됩니다. 이것은 어느 언어나 마찬가지입니다. 하지만 자바스크립트는 함수호출객체, 데이터 타입으로서의 함수, 중첩함수, 어휘적 유효범위, HTML의 엘리먼트속에서 this가 사용되는 과정에 사용자로 하여금 혼란에 빠트리게 됩니다. 여러분이 this를 완벽하게 이해하려면 아래의 코드에서 출력결과를 예측해보시기 바랍니다.




var scope = "global";


function scopeCheck() { 

var scope = "outterLocal";

alert("(1) "+this.scope); // 출력결과 예상


var object = new Object();

object.scope = "field";

object.scopeCheck = function() { alert("(2) "+this.scope); } 

object.scopeCheck(); // 출력결과 예상

function inner() { 

var scope = "innerLocal";

alert("(3) "+this.scope); 

}

inner(); // 출력결과 예상

var anotherObject = new Object();

anotherObject.scope = "anotherField";

anotherObject.scopeCheck = function() { alert("(4) "+this.scope); } 

object.scopeCheck = anotherObject.scopeCheck;

object.scopeCheck(); // 출력결과 예상
}

scopeCheck();


  

  제가 자바스크립트 과목의 교수였다면 위와 같은 문제를 냈을 겁니다. 자바스크립트를 가리키는 강의가 있기나 할진 모르겟지만.. 위 코드를 올바르게 이해한다면 this 키워드를 거의 완벽하게 이해했다고 말할 수 있습니다.

  정답은 (1) global   (2) field   (3) global   (4) field 입니다.

  그럼 해설을 해볼까요?
  


(1)

        var scope = "global";


function scopeCheck() { 

var scope = "outterLocal";

alert("(1) "+this.scope); // global


  자바스크립트는 자신을 호출한 객체를 가르킬 때 this 키워드를 사용합니다. 하지만 호출한 (명시적)객체가 없다면 호출스택을 거슬러 올라가며 가장 가까운 (명시적)객체를 찾습니다. 계속 거슬러 올라가도 (명시적)객체가 없다면 this키워드는 결국 최상단의 전역 객체를 가르키게 됩니다. 브라우저 측 자바스크립트에서는 보통 window 객체인데 이는 곧 전역을 의미합니다. 때문에 전역 변수 scope의 값인 global을 가르키게 되죠. 쉽게 이해하자면 this 키워드가 참조할 객체가 없다면 전역범위를 가리킨다고 생각하시면 되겠습니다.

  자바스크립트는 모든 호출이 객체를 통해 이루어지는 메커니즘입니다. 이를 잘 몰라도 자바스크립트를 작성하는데 문제는 없으니 시간낭비라고 생각되시면 이 설명을 건너뛰어도 좋습니다. scopeCheck라는 함수를 호출하면 사실은 묵시적 객체가 생성됩니다. 이 객체의 목적은 오직 해당 함수를 호출하기 위한 묵시적 객체입니다. 함수 내에 선언된 지역변수들은 묵시적 객체의 지역변수가 되고 호출된 함수 그 자체는 묵시적 객체의 멤버 함수로 할당되면서 함수가 시작되게 됩니다. 안타깝게도 묵시적 객체는 코드 상에서 접근할 수 있는 방법이 없는 메커니즘 상의 객체 입니다. 이와 반대로 사용자가 직접 new 키워드를 사용하여 생성한 객체가 있습니다. 이를 명시적 객체라고 하겠습니다. 명시적 객체는 얼마든지 코드 상에서 접근할 수 있습니다. 자바스크립트에서 this 키워드는 기본적으로 묵시적 객체를 참조하지 않습니다. 사용자가 new 키워드를 통해 생성한 명시적 객체만 참조하죠. 하지만 아무리 거슬러 올라가도 명시적 객체가 없다면 결국 최상단의 객체인 컨텍스트 객체(브라우저상에서는 Window 객체)를 참조하게 됩니다.




(2)

        var object = new Object();

object.scope = "field";

object.scopeCheck = function() { alert("(2) "+this.scope); } 

object.scopeCheck(); // 출력결과 예상



  이것은 전형적인 멤버함수의 호출입니다. 따라서 자연스럽게 객체의 멤버변수 scope의 값인 field를 출력하게 됩니다. 명시적 객체를 this가 바로 찾을 수 있기 때문에 global을 출력할 일이 없겠죠?






(3)
var scope = "global";

function scopeCheck() { 

var scope = "outterLocal";

function inner() { 

var scope = "innerLocal";

alert("(3) "+this.scope); 

}

}

inner(); // 출력결과 예상


  이것은 전형적인 중첩함수 nested function 입니다. 자바스크립트에서 중첩함수를 쓸 일은 생각보다 많은데, 대부분 어휘적 유효범위를 구현하기 위해서 그렇습니다. 자바스크립트 1.5는 올바른 객체지향을 지원하지 않기 때문에 클로져가 아주 유용하게 사용되죠. 어휘적 유효범위와 클로져는함수 파트에서 알아볼 것입니다. 중첩함수내의 this키워드는 명시적 객체를 찾아 거슬러 올라갑니다. inner()를 호출한 객체는... 묵시적이군 패스, scopeCheck()를 호출한 객체는... 묵시적이군 패스, 아 더이상 거슬러 올라갈 수 없구나 전역객체를 참조해야겠군. 결국 global을 출력하게 되는 것이죠. 이런 중첩함수를 만나더라도 this 키워드는 명시적 '객체'만을 참조한다는 것을 기억하면 헤깔릴 일은 없을 것입니다. 혹시 innerLocal이나 outterLocal이 출력된다고 생각했다면 다시 생각해보세요!




(4)

  

var object = new Object();

object.scope = "field";

object.scopeCheck = function() { alert("(2) "+this.scope); } 


var anotherObject = new Object();

anotherObject.scope = "anotherField";

anotherObject.scopeCheck = function() { alert("(4) "+this.scope); } 

object.scopeCheck = anotherObject.scopeCheck;

object.scopeCheck(); // 출력결과 예상

  이것은 데이터 타입으로서의 함수가 관건입니다. 

object.scopeCheck = anotherObject.scopeCheck; 

이 부분에서 anotherObject의 멤버 함수가 object의 멤버함수로 할당되고 있습니다. anotherObject의 scopeCheck함수는 사실 무명함수에 대한 참조를 가지고 있을 뿐입니다. 따라서자바스크립트에서 함수는 호출 객체와 독립적으로 존재하고 있는 것입니다! 그저 둥둥 떠있을 뿐이죠!  anotherObject.scopeCheck의 함수 참조가 object.scopeCheck에 할당되었습니다. object에서 호출된 함수는 object의 것처럼 작동합니다. 따라서 최초에는 anotherObject에 할당된 함수 였지만 scopeCheck 함수상의 this키워드는 object를 가리켜 'another field'가 아닌 'field'를 출력하게 됩니다.


위의 예제를 통해 this로 발생되는 의문을 거의 모두 해결하셨으리라 생각되는군요. 이런 딱딱한 어체는 당분간 안쓰려고 했는데 오늘만큼은 봐주세요.




THinkBerry의 생각열매를 함께 나눠요. ThinkBerry.co.kr
TAG

Leave Comments


profileThinkberry에 오신것을 환영해요~ 

Recent Trackback

오늘:
265
어제:
317
전체:
76,325