JAVA
this
: 자신을 가리키는 참조 변수
자바스크립트에서 this는 다음과 같이 동작한다.
JavaScript
this
: 해당 함수의 호출 방식에 따라 this에 바인딩 되는 객체가 달라진다.
자바스크립트의 함수 호출 방식은 모두 4가지이다.
1. (일반) 함수 호출
2. 메서드 호출
3. 생성자 함수 호출 (객체 생성 함수)
4. apply
/ call
/ bind
호출
const foo = function() {
console.log(this);
}
foo(); // window
일반 함수는 다음과 같이 가장 간단한 방법으로 호출할 수 있으며, 이때 this
는 전역 객체를 가리키게 된다.
단, 예외 상황이 하나 있다.
✅ strict mode에서는 undefined
이다.
function printThis() {
console.log(this);
}
printThis(); // window
'use strict'
function printThis() {
console.log(this);
}
printThis(); // undefined
일반 함수 호출
this
: 전역 객체에 바인딩된다.
내부 함수는 일반 함수, 메소드, 콜백함수 어디에서 선언 되었든 관계없이 this는 전역 객체를 바인딩한다.
let person = {
name: 'Hwang',
printName: function() {
console.log(this.name);
},
};
person.printName(); // "Hwang"
메소드
: 객체의 값이 함수로 이루어진 경우
객체의 메서드로 호출된 경우 this는 호출한 객체를 가리킨다.
let apple = '독이 든 사과';
let home = {
apple: '맛있는 사과',
eatApple: eatAppleFn,
}
function eatAppleFn() {
console.log(`백설공주가 ${this.apple}를 먹습니다.`);
}
// (1) 객체 method 호출
home.eatApple(); // 백설공주가 맛있는 사과를 먹습니다.
// (2) 함수 직접 호출
eatAppleFn(); // 백설공주가 독이 든 사과를 먹습니다.
let homeApple = home.eatAppleFn();
homeApple(); // 백설공주가 독이 든 사과를 먹습니다.
homeApple
의 경우 일반 함수의 형태로 호출되어 this는 window이다.
프로토타입의 this
도 호출한 객체를 가리킨다.
메서드 호출
this
: 해당 메소드를 소유한 객체에 바인딩된다.
const instance = new foo(); // instance
생성자 함수
: 객체를 생성하는 역할을 한다.
생성자 함수로 객체를 생성할 때, 생성자 함수의 this는 새로 생성된 객체를 가리킨다.
let sejelye = '백설공주';
function mirrorReply() {
console.log(`세상에서 제일 예쁜 사람은 ${this.sejelye}입니다`);
}
// 생성자 함수
function MagicMirror(name) {
this.sejelye = name;
this.reply = mirrorReply;
}
const newMirror = new MagicMirror('왕비님');
newMirror.reply(); // 세상에서 제일 예쁜 사람은 왕비님입니다.
생성자 함수의 동작 과정은 3가지로 요약할 수 있다.
1. 빈 객체 생성 및 this 바인딩:
생성자 함수가 실행되기 전, 빈 객체가 생성되고 이는 this로 바인딩된다.
2. this를 통한 프로퍼티 생성
3. 생성된 객체 반환
생성자 함수 호출
this
: 함수의 인자로 전달받은 값은 객체의 속성에 할당하기 위해 this 키워드를 사용
apply, call, bind 메소드를 통해 this를 특정 객체에 명시적으로 바인딩할 수 있다.
즉, this를 원하는 객체에 연결할 수 있다.
apply
,call
: 함수를 호출
대표적으로 유사 배열 객체에 배열 메소드를 사용하는 경우에 활용
bind
: this로 사용할 객체만 전달
메소드의 this와 메소드 내부의 중첩 함수 또는 콜백 함수의 this가 불일치하는 문제를 해결하기 위해 사용
function Person(name) {
this.name = name;
};
const foo = {};
Person.apply(foo, ['name']);
console.log(foo); // {name: 'name'}
코드에서 apply를 통해 생성자 함수 Person 내부의 this에 객체 foo를 바인딩 시켰다.
명시적 this 바인딩
this
: 특정 객체에 명시적으로 바인딩된다.
아래와 같은 콜백 함수 상황에서 bind는 유용하게 사용된다.
const person = {
name: 'Hwang',
foo(callback) {
setTimeout(callback.bind(this), 1000);
}
};
person.foo(function() {
console.log(`my name is ${this.name}`);
});
여기서 bind를 사용하지 않으면, this는 person의 객체가 아닌 일반 함수에서 호출되어 전역 객체를 가리키게 된다.
(콜백 함수는 전역 객체 바인딩이기 때문)
apply
와 call
의 차이점call 메소드는 인자 하나 하나를, apply는 인자 리스트를 전달한다.
매개변수를 배열로 넣어야 한다면 apply를 사용하면 된다.
obj.call(obj1,'my','name','is','dobby');
obj.apply(obj2,['my','name','is','dobby']);
함수를 event handler로 사용하는 경우, this는 이벤트를 발생시킨 요소로 설정된다.
EventHandler
에서의 this는 handler 함수를 등록한 element
를 가리킨다.
만약 외부의 this를 참조하려 한다면, 앞에서 살펴본 bind 등을 이용하여 명시적으로 바인딩시켜주어야 한다.
<button id="btn1">eventHandler</button>
<button id="btn2">eventHandler_bind</button>
<script>
function alertThis() {
alert('this: ' + this);
}
document.getElementById("btn1").addEventListener("click", alertThis); // this: HTMLButtonElement
document.getElementById("btn2").addEventListener("click", alertThis.bind(this)); // this: window
</script>
화살표 함수에서는 this가 조금 달라진다.
화살표 함수가 나오기 전까지 함수는, 어떻게 호출되는지에 따라 자신의 this 값을 정의했다.
하지만, 화살표 함수는 자신을 포함하고 있는 외부 Scope에서 this를 계승받는다.
화살표 함수에는 this라는 변수 자체가 존재하지 않기 때문에 그 상위 환경에서의 this를 참조하게 된다.
즉, 화살표 함수에서 this는 자신을 감싼 정적 범위
이다.
JavaScript에서는 어떤 식별자를 찾을 때 현재 환경에서 그 변수가 없다면 바로 상위 환경을 검색한다.
그렇게 점점 상위 환경으로 타고 올라가다 변수를 찾거나 가장 상위 환경에 도달하면 탐색을 멈춘다.
화살표 함수에서의 this 바인딩 방식도 이와 유사하다.
일반 함수에서의 this: window (전역 객체)
내부 함수(일반 함수, 메소드, 콜백함수)는 모두 전역객체 바인딩
객체 메소드 또는 프로토타입 메소드에서 this: 메소드를 소유한(호출한) 객체
생성자 함수에서 this: 객체 속성 할당을 위해 사용(생성한 객체를 참조)
명시적 this: 특정 객체에 바인딩 가능 (apply, call, bind)
DOM event handler로 사용되는 함수 내부의 this: 이벤트가 발생한 element
화살표 함수에서 this: 자신을 감싼 상위 환경의 this 참조