📌 this 란

실행할 코드에 제공할 환경 정보들을 모아놓은 객체를 실행 컨텍스트(execution context) 라고 부른다. 자바스크립트 내부에서 이런 실행 컨텍스트를 스택(Stack)으로 관리하고 있으며, 실행되는 시점에서 자주 변경되는 실행 컨텍스트를 this 가 가리키고있다. 

 

스택 중 콜스택(Call Stack)에 쌓아올리며 가장 위에 쌓여있는 컨텍스트와 관련된 코드를 실행하는 방법으로 코드의 환경과 순서를 보장 할 수 있다.

 

 

객체 지향 언어에서 this는 클래스로 생성한 인스턴스를 말하지만, 자바스크립트에서 this는 언제 어디서나 사용할 수 있다.

this는 실행되는 코드의 실행 컨텍스트를 가리킨다!

💡 실행 컨텍스트 속 3가지
VariableEvironment
LexicalEvironment
ThisBinding 👉🏻 오늘 이해할 것

 

 

 

1. default binding

기본적으로 this는 전역 객체를 가리킨다. 브라우저 환경에서 this는 window를 가르키고, 노드 환경에서 this는 global을 가르킨다.

Browser

 

Node

 

 

 

2. 메서드 내부에서의 this

함수 함수는 호출의 주체가 없고 함수 그 자체로 독립적인 기능을 수행한다.
메서드 반대로 메서드는 호출 주체가 있으며 자신을 호출한 대상 객체에 대한 동작을 수행한다.

 

함수

함수명();
// CASE1 : 함수
// 호출 주체를 명시할 수 없기 때문에 this는 전역 객체를 의미
var func = function (x) {
console.log(this, x);
};
func(1); // Window { ... } 1

메서드

객체.메서드();
// CASE2 : 메서드
// 호출 주체를 명시할 수 있기 때문에 this는 해당 객체(obj)를 의미
// obj는 { method: func }
var obj = {
method: func,
};
obj.method(2); // { method: [Function: func] } 2

 

 

예외

메서드 내부에서도 독립적으로 호출한다면 this는 전역 객체를 의미한다.

var obj1 = {
    outer: function () {
        console.log(this); // (1)
        var innerFunc = function () {
            console.log(this); // (2), (3)
        }
        innerFunc();
        var obj2 = {
            innerMethod: innerFunc
        };
        obj2.innerMethod();
    }
};
obj1.outer();
실행결과
(1) : obj1
(2) : 전역객체
(3) : obj2

 

 

 

3. this 우회

화살표(=>)함수는 실행 컨텍스트를 생성할 때 바인딩 과정이 없다. 일반함수와 화살표 함수의 가장 큰 차이점은 this binding 의 여부이다.

var obj = {
    outer: function () {
        console.log(this); // (1) obj
        var innerFunc = () => {
            console.log(this); // (2) obj
        };
        innerFunc(); //함수로 호출해도 전역객체가 아닌 호출객체를 가리킴
    }
}
obj.outer();

 

화살표 함수 예외

obj 객체 안 print 메서드를 화살표 함수로 선언할 경우 this는 전역 객체를 가리킨다. 

var obj = {
    names: ["seo"],
    text: "님 안녕하세요",
    print: () => { console.log(this.text) } // undefined
}
obj.print()

 

 

4. 콜백함수 this

콜백함수도 함수이기때문에 this가 전역 객체를 가리키지만 콜백함수를 넘겨 받은 함수에서 콜백함수에 별도로 this를 지정해준 경우 예외로 그 대상을 참조한다.

 

 

별도의 지정이 없어 전역 객체를 가리킨다.

setTimeout(function () { console.log(this) }, 300);
[1, 2, 3, 4, 5].forEach(function(x) {
	console.log(this, x);
});

 

addEventListener 메서드는 콜백함수 호출 시, 자신의 this를 상속. 따라서 this는 button 을 가리킨다.

document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function (e) {
    console.log(this, e);
});

 

 

5. 명시적 this 바인딩

 

자동으로 부여되는 상황별 this의 규칙을 깨고 this에 별도의 값을 저장하는 방법

call, apply, bind
call 호출 주체인 함수를 즉시 실행 첫번째 인자로 실행 컨텍스트를 인자로 전달
apply call과 동일하되 배열 형태로 넘김
bind 즉시 호출하지 않고, 함수에 this를 미리 적용하거나 부분적으로 적용  

 

 

5-1. Call 메서드

var obj = {
    string : "free",
    value : function(){
        console.log(this.string);
    },
}

var obj2 = {
    string : "not free",
}

obj.value(); //free
obj.value.call(obj2); //not free
var func = function (a, b, c) {
    console.log(this, a, b, c);
};
// no binding
func(1, 2, 3); // Window{ ... } 1 2 3

// 명시적 binding
func.call({ x: 1 }, 4, 5, 6}; // { x: 1 } 4 5 6
var obj = {
    a: 1,
    method: function (x, y) {
        console.log(this.a, x, y);
    }
};
obj.method(2, 3); // 1 2 3
obj.method.call({ a: 4 }, 5, 6); // 4 5 6

 

 

5-2. Apply 메서드

var func = function (a, b, c) {
    console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6
var obj = {
    a: 1,
    method: function (x, y) {
        console.log(this.a, x, y);
    }
};
obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6

 

 

5-3. Bind 메서드

call과는 다르게 즉시 호출하지는 않고 넘겨받은 this 및 인수들을 바탕으로 새로운 함수 를 반환하는 메서드

var func = function (a, b, c, d) {
    console.log(this, a, b, c, d);
};
func(1, 2, 3, 4); // window ... 1, 2, 3, 4

// 함수에 this 미리 적용
var bindFunc1 = func.bind({ x: 1 }); // 바로 호출X
bindFunc1(5, 6, 7, 8); // { x: 1 } 5 6 7 8

// 부분 적용 함수 구현
var bindFunc2 = func.bind({ x: 1 }, 4, 5); // 4와 5를 미리 적용
bindFunc2(6, 7); // { x: 1 } 4 5 6 7
bindFunc2(8, 9); // { x: 1 } 4 5 8 9

 

+ Recent posts