June 10, 2023
자바스크립트의 this는 함수가 어떻게 호출되는지에 따라 동적으로 할당된다.
전역 객체는 모든 객체의 유일한 최상위 객체이다. 브라우저의 경우 window
, 서버의 경우 global
객체를 의미한다.
전역 객체는 전역 스코프를 갖는 전역 변수를 프로퍼티로 소유한다. 글로벌 영역에서 선언된 함수의 경우 전역 객체의 프로퍼티로
접근할 수 있는 전역 변수의 메서드이다.
// browser
this === window;
// server (node.js)
this === global;
기본적으로 this
는 전역 객체에 바인딩되는데 추가적으로 다음과 같은 케이스 또한 전역 객체에 바인딩된다.
중첩된 함수 구조를 가진,
function a() {
console.log(this); // window
function b() {
console.log(this); // window
}
}
var obj = {
a: function() {
console.log(this); // window
function b() {
console.log(this); // window
}
},
};
var obj = {
a: function() {
setTimeout(function b() {
console.log(this); // window
}, 100);
},
};
즉, 내부 함수는 일반 함수, 메서드, 콜백 함수 어디에서 선언되었는지 관계없이 this는 전역 객체에 바인딩된다.
함수가 객체의 프로퍼티 값이면 메서드로서 호출된다. 이때 this
는 해당 메서드를 소유한 객체가 바인딩된다.
프로토타입 객체도 메서드를 가질 수 있는데, 프로토타입 객체 메서드 내부에서 사용된 this
도 일반 메서드 방식과
동일하게 해당 메서드를 호출한 객체에 바인딩된다.
var obj1 = {
name: 'Lee',
sayName: function() {
console.log(this.name);
},
};
var obj2 = {
name: 'Kim',
};
obj2.sayName = obj1.sayName;
obj1.sayName(); // Lee
obj2.sayName(); // Kim
function Person(name) {
this.name = name;
}
Person.prototype.getName = function() {
return this.name;
};
var me = new Person('Lee');
console.log(me.getName());
Person.prototype.name = 'Kim';
console.log(Person.prototype.getName());
기존 함수에 new 연산자를 붙여 호출한 해당 함수는 생성자 함수로 동작한다. 생성자 함수로 호출된 함수는 this 바인딩이 다르게 동작하게 되는데, new 연산자와 함께 생성자 함수를 호출하면 다음과 같은 순서로 동작한다.
this
는 생성된 빈 객체를 가리키게 된다. 추가적으로 생성자 함수의 prototype 프로퍼티가 가리키는 객체를 자신의 프로토타입 객체로 설정한다.this
를 통한 프로퍼티 생성, 생성된 빈 객체에 this
를 사용하여 동적으로 프로퍼티와 메서드를 생성할 수 있다. this
는 새로 생성된
객체를 가리키므로 this를 통해 생성한 프로퍼티와 메서드는 새로 생성된 객체에 추가된다.function Person(name) {
// 생성자 함수 코드 실행 전 -------- 1
this.name = name; // --------- 2
// 생성된 함수 반환 -------------- 3
}
var me = new Person('Lee');
console.log(me.name); // Lee
위처럼 자바스크립트 엔진에 의해 동적으로 할당되는 this와는 달리, 명시적으로 바인딩할 수 있는 방법을 제공한다.
func.apply(thisArg, [argsArray]);
// thisArg, 함수 내부의 this에 바인딩할 객체
// argsArray, 함수에 전달할 argument의 배열
call과 apply의 기능은 동일하지만, apply는 배열 형태로, call은 하나씩 넘긴다.
Person.apply(foo, [1, 2, 3]);
Person.call(foo, 1, 2, 3);
bind의 경우 ES5에 추가되었다. 함수에 인자로 전달한 this가 바인딩된 새로운 함수를 반환한다. 즉, apply, call과의 차이점은 바로 함수가 호출되는 것이 아닌 함수를 반환받는다는 점이다.
화살표 함수의 경우 ES6에 새롭게 추가되었다. 일반적으로 함수는 어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정되는데, 화살표 함수의 경우는 다르다.
화살표 함수의 this는 언제나 상위 스코프의 this를 가리킨다. 이를 렉시컬 this라고 한다.
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function(arr) {
// this는 상위 스코프인 prefixArray 메소드 내의 this를 가리킨다.
return arr.map(x => `${this.prefix} ${x}`);
};
const pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));
이러한 특성 때문에 화살표 함수의 사용을 피해야 하는 몇 가지 경우가 있다.