IT_Programming/JavaScript

[펌] This 키워드

JJun ™ 2010. 3. 31. 11:09

-------------------------------------------------------------------------------------------------

                                                    출처: http://www.quirksmode.org/js/this.html

-------------------------------------------------------------------------------------------------

 

One of the most powerful JavaScript keywords is this. Unfortunately it is hard to use if you don't exactly know how it works. Below I explain how to use it in event handling. Later on I'll add some information about other uses of this.

Owner

The question that we'll discuss for the remainder of the page is: What does this refer to in the function doSomething()?

function doSomething() {
   this.style.color = '#cc0000';
}

 

In JavaScript this always refers to the “owner” of the function we're executing, or rather,

to the object that a function is a method of. When we define our faithful function doSomething() in a page, its owner is the page, or rather, the window object (or global object) of JavaScript. An onclick property, though, is owned by the HTML element it belongs to.

This "ownership" is the result of JavaScript's object oriented approach. See the Objects as associative arrays page for some more information. 

 

If we execute doSomething() without any more preparation the this keyword refers to the window and the function tries to change the style.color of the window. Since the window doesn't have a style object the function fails miserably and produces JavaScript errors.

 

 

Copying

So if we want to use this to its full extent we have to take care that the function that uses it is "owned" by the correct HTML element. In other words, we have to copy the function to our onclick property. Traditional event registration takes care of it.

element.onclick = doSomething;

The function is copied in its entirety to the onclick property (which now becomes a method).

So if the event handler is executed this refers to the HTML element and its color is changed.

 

 

The trick is of course that we can copy the function to several event handlers.

Each time this will refer to the correct HTML element:

 

Thus you use this to the fullest extent. Each time the function is called, this refers to the HTML element that is currently handling the event, the HTML element that "owns" the copy of doSomething().

 

 

Referring

However, if you use inline event registration

<element onclick="doSomething()">

you do not copy the function! Instead, you refer to it, and the difference is crucial.

The onclick property does not contain the actual function, but merely a function call:

doSomething();

So it says “Go to doSomething() and execute it.”

When we arrive at doSomething() the this keyword once again refers to the global window object

and the function returns error messages.

 

 

 

 

The difference

If you want to use this for accessing the HTML element that is handling the event, you must make sure that the this keyword is actually written into the onclick property. only in that case does it refer to the HTML element the event handler is registered to. So if you do

element.onclick = doSomething;
alert(element.onclick)

you get

function doSomething()
{
	this.style.color = '#cc0000';
}

As you can see, the this keyword is present in the onclick method.

Therefore it refers to the HTML element. But if you do

<element onclick="doSomething()">
alert(element.onclick)

 

you get

function onclick()
{
	doSomething()
}

 

This is merely a reference to function doSomething().

The this keyword is not present in the onclick method so it doesn't refer to the HTML element.

 

 

Examples - copying

this is written into the onclick method in the following cases:

element.onclick = doSomething
element.addEventListener('click',doSomething,false)
element.onclick = function () {this.style.color = '#cc0000';}
<element onclick="this.style.color = '#cc0000';">

Examples - referring

In the following cases this refers to the window:

element.onclick = function () {doSomething()}
element.attachEvent('onclick',doSomething)
<element onclick="doSomething()">

 

Note the presence of attachEvent().

The main drawback of the Microsoft event registration model is that attachEvent() creates a reference to the function and does not copy it. Therefore it is sometimes impossible to know which HTML currently handles the event.

 

 

Combination

When using inline event registration you can also send this to the function so that you can still use it:

<element onclick="doSomething(this)">
function doSomething(obj) {
	// this is present in the event handler and is sent to the function
	// obj now refers to the HTML element, so we can do
	obj.style.color = '#cc0000';
}

 

 

 


 

 

 

출처: http://thinkberry.co.kr/textyle/728

 

 

자바스크립트 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로 발생되는 의문을 거의 모두 해결하셨으리라 생각되는군요.

이런 딱딱한 어체는 당분간 안쓰려고 했는데 오늘만큼은 봐주세요.