꾸준한 개발자

계속적인 성장을 추구하는 개발자입니다. 꾸준함을 추구합니다.

계속 쓰는 개발 노트

JAVASCRIPT/자바스크립트 이론

this

gold_dragon 2022. 11. 22. 21:06

this가 어떤 값에 바인딩 되는지는 실행 컨텍스트가 생성될 때 결정됩니다. 즉 함수를 호출할 때 결정된다 볼 수 있습니다.

그러다보니 함수를 어떻게 호출하는지에 따라 바인딩되는 값이 달라지게 됩니다.

전역 스코프에서 쓰이는 this

전역 스코프에서 쓰이는 this는 전역 객체에 바인딩 됩니다. 브라우저 환경에서는 window, node 환경에서는 global에 바인딩 됩니다.

메서드로서 호출될 때 메서드 안에 있는 this

함수와 메서드를 구분할 수 있는 것은 독립성에 있습니다. 함수의 경우 독립적으로 실행되는 반면, 메서드의 경우 자신을 호출하는 객체에 관한 동작을 수행합니다.

var func = function (param) {
    console.log(this, x);
};

func(1);

var obj = {
    method: func
};

obj.method(2);

위 예제에서 함수와 메서드의 차이를 알 수 있습니다.

func변수에 익명함수를 할당하고, 독립적으로 호출할 경우와 객체의 프로퍼티에 func 함수를 할당해서 obj 객체의 메서드로 호출할 경우가 있습니다.

func 함수를 독립적으로 호출할 경우 this는 window 전역 객체에 바인딩되고, obj의 메서드로 호출될 경우 this가 obj 객체에 바인딩 되는 것을 확인할 수 있습니다.

함수로서 호출될 때 함수 안에 있는 this

위 내용에서 알 수 있듯이 독립적으로 함수를 호출할 경우 this는 전역 객체에 바인딩 됩니다.

메서드 내부에 구현된 this라도 독립적으로 함수를 호출 시 전역 객체에 바인딩 됩니다.

var obj1 = {
    outer: function () {
        console.log(this); // obj1
        
        var innerFunc = function () {
            console.log(this);
        }
        
        innerFunc(); // window
        
        var obj2 = {
            innerMethod: innerFunc
        };
        
        obj2.innerMethod(); // obj2
    }
}

innerFunc와 같이 메서드 안에 구현된 this라도 어떻게 호출되냐에 따라 바인딩되는 객체가 달라집니다.

콜백 함수 호출 시, 해당 함수 안에 있는 this

setTimeout(function () { console.log(this); }, 300); // window

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

document.body.innerHTML += '<button id="a">버튼</button>';
document.body.querySelector('#a').addEventListener('click', function (e) {
    console.log(e);
}); // 버튼 element 객체

setTimeout 함수와 forEach 메서드는 내부에서 콜백 함수를 호출 할 때 대상이 될 this를 바인딩해주지 않았습니다. 한편 addEventListener 메서드는 콜백 함수를 호출할 때 자신이 this를 상속하도록 정의돼 있기 때문에 점(.) 앞부분에 this가 바인딩 됩니다.

생성자 함수 안에 있는 this

var Cat = function (name, age) {
    this.bark = '야옹';
   	this.name = name;
    this.age = age;
};

var choco = new Cat('초코', 5);
console.log(choco); // Cat { bark: '야옹', name: '초코', age: 5 }

Cat이란 변수에 익명 함수를 할당했습니다. new 명령어와 같이 Cat 함수를 호출하게 되면 해당 함수 내부의 this는 choco 인스턴스에 바인딩 되는 것을 확인할 수 있습니다.

명시적인 this 바인딩

위 예제에서 innerFunc 함수 내부에 명시적으로 this 바인딩 객체를 지정해 줄 수 있습니다.

ES6 이전에는 변수를 활용해서 this 바인딩을 명시해줄 수 있었습니다.

var obj1 = {
    outer: function () {
        console.log(this); // obj1
        
        var self = this;
        
        var innerFunc = function () {
            console.log(self);
        };
        
        innerFunc(); // obj1
    }
}

outer 스코프에서 this의 바인딩 값을 self 변수에 할당한 후 innerFunc 함수에서 활용하는 방법입니다.

또 다른 방법으로는 화살표 함수를 사용하는 것입니다.

var obj1 = {
    outer: function () {
        console.log(this); // obj1
        
        var innerFunc = () => {
            console.log(this);
        };
        
        innerFunc(); // obj1
    }
}

화살표 함수는 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠집니다. 그러다보니 상위 스코프의 this를 그대로 활용할 수 있습니다.

call, apply, bind 메서드를 활용해서 함수를 호출할 때 this 바인딩을 명시해줄 수 있습니다.

var obj1 = {
    outer: function () {
        console.log(this); // obj1
        
        var innerFunc = function () {
            console.log(this);
        };
        
        innerFunc.call(this); // obj1
        innerFunc.apply(this); // obj1
        innerFun.bind(this)(); // obj1
    }
}

call, apply의 경우 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령입니다. 첫 번째 인자를 this로 바인딩하고, 이후 인자들의 경우 호출하는 함수의 매개변수로 사용됩니다. call의 경우 쉼표(,)로 인자들을 정의하고, apply의 경우 배열로 정의합니다.

bind의 경우 call, apply와 다르게 즉시 호출하지 않습니다. 인자들은 배열 형태로 정의합니다. 혹은 부분 적용 함수로서 인자를 넘겨줄 수 있습니다.

 

콜백 함수의 경우 별도의 인자로 this를 받는 경우가 있습니다.

Array.prototype.forEach(callback[, thisArg])
Array.prototype.map(callback[, thisArg])
Array.prototype.filter(callback[, thisArg])
Array.prototype.some(callback[, thisArg])
...

 

'JAVASCRIPT > 자바스크립트 이론' 카테고리의 다른 글

호이스팅  (0) 2022.12.04
원시타입과 참조타입 (Primitive type & Reference type)  (0) 2022.11.21
타입이란  (0) 2021.02.16
currying이란  (0) 2021.02.05
REST API란  (2) 2021.02.03