3장 this
3-1 상황에 따 달라지는 this
- js에서 this는 실행 컨텍스트가 생성될 때 함께 결정됨.
- 실행컨텍스트는 함수를 호출할 때 생성되므로 this는 함수를 호출할 때 결정됨
3-1-1 전역공간에서의 this
- 전역 공간에서는 this 가 전역 객체를 가르킴
- 브라우저에서는 window
- Node.js에서는 global
var a = 1;
console.log(a);
console.log(window.a);
console.log(this.a);
- 위와 같이 뜨는 이유는 js의 모든 변수는 실행 컨텍스트의 LexicalEnnvironment의 프로퍼티로 동작하기 때문.
- 전역 변수 선언시, js는 전역 객체의 프로퍼티로 할당함
var a = 1;
delete window.a;
var b = 2;
delete b;
window.c = 3;
delete window.c;
window.d = 4;
delete d;
- 처음부터 전역객체의 프로퍼티로 할당했으면 삭제 O
- 전역변수로 선언한 경우에는 삭제 X
3-1-2 메서드로서 호출할 때 그 메서드 내부에서의 this
- 함수 vs 메서드
- 함수와 메서드를 구분하는 것은 독립성에 있음
- 함수는 그 자체로 독립적인 기능 수행
- 메서드는 자신이 호출한 대상 객체에 관한 동작 수행
var func = function (x) {
console.log(this, x);
};
func(1);
var obj = {
method: func,
};
obj.method(2);
3-1-3 함수로서 호출할 때 그 함수 내부에서의 this
-
함수 내부에서의 this
- 어떤 함수를 함수로서 호출할 경우는 this가 지정되지 않음.
- this는 전역 객체를 가르킴
-
메서드의 내부함수에서의 this
var obj1 = {
outer: function () {
console.log(this);
var innerFunc = function () {
console.log(this);
};
innerFunc();
var obj2 = {
innerMethod: innerFunc,
};
obj2.innerMethod();
},
};
obj1.outer();
- (1): obj1, (2): 전역객체(Window), (3): obj2 출력
- outer 메서드 내부에 있는 함수(innerFunc)를 함수로서 호출하고, obj2.innerMethod(); 같은 함수를 메서드로서 호출함. 이처럼 같은 함수여도 바인딩되는 this의 대상이 달라짐.
- this 바인딩은 함수를 실행하는 당시의 주변 환경(메서드 내부인지, 함수 내부인지)는 중요하지 않고, 오직 해당 함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지의 여부가 관건
-
메서드의 내부 함수에서의 this를 우회하는 방법
- 변수를 활용하는 것
- 상위 스코프의 this를 변수에 저장해 내부 함수에서 활용.
var obj1 = {
outer: function () {
console.log(this);
var innerFunc = function () {
console.log(this);
};
innerFunc();
var self = this;
var innerFunc2 = function () {
console.log(self);
};
innerFunc2();
},
};
obj1.outer();
-
this를 바인딩하지 않는 함수
3-1-4 콜백 함수 호출 시 그 함수 내부에서의 this
- 콜백 함수도 함수이기 때문에 기본적으로는 this가 전역 객체를 참조
- 제어권을 받은 함수에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 가리킴
3-1-5 생성자 함수 내부에서의 this
- 생성자는 구체적인 인스턴스를 만들기 위한 일종의 틀임.
- 생성자 함수는 공통된 성질을 지니는 객체들을 생성하는 데 사용하는 함수로, new 명령어와 함께 함수를 호출하면 해당 함수가 생성자 함수로서 동작.
- 생성자 함수로서 호출되는 경우 내부에서의 this는 곧 새로 만들 구체적인 인스턴스 자신이 됨.
3-2 명시적으로 this를 바인딩하는 방법
3-2-1 call 메서드
Function.prototype.call(thisarg [, arg1[, arg2[, ...]]])
- call 메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령
- 이때 call 메서드의 첫 번째 인자를 this로 바인딩하고, 이후의 인자들을 호출할 함수의 매개변수로 함.
3-2-2 apply 메서드
Function.prototype.apply(thisarg [, argsArray])
- apply는 call과 기능적으로 완전히 동일
- 두 번째 인자를 배열로 받아 그 배열의 요소들을 호출할 함수의 매개변수로 지정한다는 점이 차이점.
3-2-3 call / apply 메서드의 활용
- 유사배열 객체에 배열 메서드를 적용
- ES6에서는 유사배열객체 또는 순회 가능한 모든 종류의 데이터 타입을 배열로 전환하는 Array.from을 도입
- 생성자 내부에서 다른 생성자를 호출
- 생성자 내부에 다른 생성자와 공통된 내용이 있을 경우에 call or apply를 이용해 다른 생성자를 호출하면 간단하게 반복을 줄일 수 있음
- 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 - apply 활용
- ES6에서는 spread operator를 이용하면 apply를 적용하는 것보다 간편하게 작성 가능
3-2-4 bind 메서드
Function.prototype.bind(thisarg [, arg1[, arg2[, ...]]])
- ES5에서 추가된 기능으로, call 메서드와 비슷하지만 즉시 호출하지 않고, this 및 인수들을 바탕으로 새로운 함수를 반환하는 메서드
- (1) 함수에 this를 미리 적용, (2) 부분 적용 함수를 구현하는 2가지의 목적
- name 프로퍼티
- bind 메서드를 적용해서 새로 만든 함수는 name 프로퍼티에 동사 bind의 수동태인 'bound'라는 접두어가 붙음
- 기존의 call이나 apply보다 코드를 추적하기 쉬움
- 상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기
- 변수를 활용하여 우회하는 방법도 있지만, call, apply, bind 메서드를 사용하면 더 깔끔하게 처리 가능함.
- 콜백 함수를 인자로 받는 함수나 메서드 중에서 기본적으로 콜백 함수 내에서의 this에 관여하는 함수 또는 메서드에 대해서도 bind 메서드를 이용하면 this 값을 사용자에 맞춰서 바꿀 수 있음
3-2-5 화살표 함수의 예외사항
- 화살표 함수 내부에는 this가 아예 없으며, 접근하고자 하면 스코프체인 상 가장 가까운 this에 접근하게 됨
3-2-6 별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)
- 내부 요소에 대해 같은 동작을 반복 수행해야 하는 배열 메서드에 많이 포진돼있음.
- 콜백 함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체(thisArg)를 인자로 지정할 수 있는 경우가 있음
- ex) forEach, map, filter, some, every, find, findIndex, flatMap, from
정리