다른 대부분의 객체지향 언어에서 this는 클래스로 생성한 인스턴스 객체를 의미한다. 클래스에서만 사용할 수 있기 때문에 혼란의 여지가 별로 없다.
그러나 자바스크립트의 this는 어디서든 사용할 수 있다.
함수와 객체(메서드)의 구분이 느슨한 자바스크립트에서 this는 실질적으로 이 둘을 구분하는 유일한 기능이다.
상황에 따라 달라지는 this
자바스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다. 실행컨텍스트는 함수를 호출할 때 생성되므로, 바꿔 말하면 this는 함수를 호출할 때 결정된다고 할 수 있다.
함수를 어떤 방식으로 호출하느냐에 따라 값이 달라지는 것이다.
전역 공간에서의 this
전역 공간에서 this는 전역 객체를 가리킨다. 전역 컨텍스트를 생성하는 주체가 전역 객체이기 때문이다.
전역 공간에서의 특이한 성질
전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로도 할당한다.
변수이면서 객체의 프로퍼티이기도 한 셈.
자바스크립트의 모든 변수는 실은 특정 객체의 프로퍼티로 동작한다. 사용자가 var 연산자를 이용해 변수를 선언하더라도 실제 자바스크립트 엔진은 어떤 특정 객체(L.E)의 프로퍼티로 인식한다.
어떤 변수를 호출하면 L.E를 조회해서 일치하는 프로퍼티가 있을 경우 그 값을 반환한다. 전역 컨텍스트의 경우 L.E는 전역객체를 그대로 참조한다.
따라서 앞의 전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로도 할당한다는 말은 틀렸다.
정확하게, 전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다.
그러나 삭제 명령에 대해, 전역변수 선언과 전역객체의 프로퍼티 할당은 전혀 다르다.
처음부터 전역객체의 프로퍼티로 할당한 경우에는 삭제가 되는 반면,
전역변수로 선언한 경우에는 삭제가 되지 않는다.
(사용자가 의도치 않게 삭제하는 것을 방지하는 차원임)
var로 선언한 전역변수와 전역객체의 프로퍼티는 호이스팅 여부 및 configurable 여부에서 차이를 보인다.
메서드로서 호출할 때 그 메서드 내부에서의 this
함수 vs 메서드
함수를 실행하는 두 가지 방법에는,
1) 함수로 호출하는 경우
2) 메서드로 호출하는 경우
함수와 메서드의 차이는 독립성에 있다.
함수는 그 자체로 독립적인 기능을 수행하는 반면, 메서드는 자신을 호출한 대상 객체에 관한 동작을 수행한다.
흔히 생각하는, 메서드는 '객체의 프로퍼티에 할당된 함수'라는 말은 반은 맞고 반은 틀리다.
객체의 메서드로 호출할 경우에만 메서드로 동작하기 때문이다.
var func = function(x){
console.log(this, x);
};
func(1);
var obj = {
method: func
};
obj.method(2);
함수로서의 호출과 메서드로서의 호출은 함수 앞에 점(.)의 여부로 구분할 수 있다. (혹은 대괄호로 암수 앞에 객체가 명시되어 있는 경우가 메서드임)
메서드 내부에서의 this
this에는 호출한 주체에 대한 정보가 담긴다.
점 표기법의 경우 마지막 점 앞에 명시된 객체가 곧 this가 된다.
함수로서 호출할 때 그 함수 내부에서의 this
함수 내부에서의 this
어떤 함수를 함수로서 호출할 경우에는 this가 지정되지 않는다.
함수로서 호출하는 것은 호출주체를 명시하지 않고 개발자가 직접 관여해서 실행한 것이기 때문에 호출 주체의 정보를 알 수 없다.
따라서 함수에서의 this는 전역객체를 가리킨다.
메서드 내부함수에서의 this
var obj1 = {
outer: function(){
console.log(this); //(1)
var innerFunc = function(){
console.log(this); //(2) (3)
}
innerFunc();
var obj2 = {
innerMethod: innerFunc
};
obj1.innerMethod();
}
};
obj1.outer();
this바인딩에 관해, 함수를 실행하는 당시의 주변환경은 중요하지 않고, 오직 해당 함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지 없는지가 관건인 것이다.
메서드의 내부 함수에서 this를 우회하는 방법
호출 주체가 없을 때 자동으로 전역객체를 바인딩하지 않고 호출 당시 주변 환경의 this를 그대로 상속받아 사용할 수 있다면 좋겠지만, ES5까지는 자체적으로 내부함수에 this를 상속할 방법이 없다.
그러나 변수를 사용함으로 내부함수에서 this를 우회할 수 있다.
this를 바인딩하지 않는 함수
ES6는 함수 내부에서 this가 전역객체를 바라보는 문제를 보완하고자 this를 바인딩하지 않는 함수를 새로 도입했다.
화살표함수는 실행컨텍스트를 생성할 때 this 바인딩 과정 자체가 빠지게 되어, 상위 스코프의 this를 그대로 활용할 수 있다.
콜백 함수 호출 시 그 함수 내부에서의 this
함수 a의 제어권을 다른 함수(메서드) b에게 넘겨주는 경우 함수 a를 콜백함수라고 한다.
이때 함수a는 함수b의 내부 로직에 따라 실행되며, this역시 함수 b로직에서 정한 규칙에 따라 값이 결정된다.
콜백함수도 함수이기 때문에 기본적으로 this가 전역객체를 참조하지만, 제어권을 받은 함수에서 콜백함수에 별도로 this가 될 대상을 지정할 경우에는 그 대상을 참조하게 된다.
콜백함수에서의 this는 무조건 이렇다고 정의할 수 없다.
콜백함수의 제어권을 가지는 함수가 콜백함수에서의 this를 무엇으로 할지를 정하며, 특별히 정의하지 않은 경우에는 함수와 마찬가지로 전역객체를 바라본다.
생성자 함수 내부에서의 this
생성자 함수는 어떤 공통된 성질을 지니는 객체들을 생성하는데 사용하는 함수이다.
객체지향언어에서는 생성자를 클래스, 클래스를 통해 만든 객체를 인스턴스라고 한다.
자바스크립트는 함수에 생성자로서의 역할을 함께 부여했다.
new 명령어와 함께 함수를 호출하면 해당 함수가 생성자로서 동작하게 된다.
그리고 어떤 함수가 생성자 함수로 호출된 경우, 내부에서의 this는 새로 만들 구체적인 인스턴스 자신이 된다.
명시적으로 this를 바인딩하는 방법
상황별로 this가 바인딩되기도 하지만, 규칙을 깨고 this에 별도의 대상을 바인딩하는 방법도 있다.
call메서드
call메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령이다.
call메서드의 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 한다.
함수를 그냥 실행하면 this는 전역객체를 참조하지만, call메서드를 이용하면 임의의 객체를 this로 지정할 수 있다.
apply메서드
call메서드와 기능적으로 동일하다.
다만, 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다는 점에서 차이가 있다.
-여러 개의 인수를 받는 메서드에게 하나의 배열로 인수를 전달하고 싶을 때 apply메서드를 사용하면 좋다.
-> 해당 메서드들을 이용해 유사배열객체에 배열메서드를 적용할 수 있다.
명시적으로 this를 바인딩하면서 함수 또는 메서드를 실행하는 훌륭한 방법이지만,
오히려 이로 인해 this를 예측하기 어렵게 만들어 코드 해석을 방해하기도 한다.
생성자 내부에서 다른 생성자를 호출
생성자 내부에 다른 생성자와 공통된 내용이 있을 경우, 앞의 두 함수를 이용해 생성자를 호출하면 간단하게 반복을 줄일 수 있다.
bind메서드
call과 비슷하지만, 즉시 호출하지는 않고, 넘겨받은 this인수들을 바탕으로 새로운 함수를 반환하는 메서드이다.
다시 새로운 함수를 호출할 때 인수를 넘기면 그 인수들은 기존 bind메서드를 호출할 때 전달했던 인수들의 뒤에 이어서 등록된다.
즉, bind메서드는 함수에 this를 미리 적용하는 것과 부분 적용 함수를 구현하는 두 가지 목적을 모두 지닌다.
name프로퍼티
bind메서드를 적용해 새로 만든 함수는 name프로퍼티에 수동태 bound라는 접두어가 붙는다.
코드를 추적하기에 더 수월하다.
화살표 함수의 예외사항
ES6에 새롭게 도입된 화살표 함수는 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외되었다.
즉, 이 함수 내부에는 this가 아예 없으며, 접근하고자 하면 스코프체인상 가장 가까운 this에 접근하게 된다.
'자바스크립트 공부하기' 카테고리의 다른 글
[코어자바스크립트] 클로저 (0) | 2021.06.24 |
---|---|
[코어자바스크립트] 04. 콜백함수 (0) | 2021.06.22 |
[코어자바스크립트] 02.실행 컨텍스트 (0) | 2021.05.13 |
[코어자바스크립트] 1단원 정리 (0) | 2021.05.11 |
[코어자바스크립트] 6.undefined와 null (0) | 2021.05.11 |