[JS] this란? 모든 케이스를 정리해보자
[JS] this란? 모든 케이스를 정리해보자
⚡️ this란?
'그'는 나에게로 와서 꽃이 되었다.
위 문장에서 '그'
는 누굴까? 상황에 따라 바뀔 것이다. 옆집 아저씨가 될 수도 있고, 할아버지가 될 수도 있고, 편의점 알바생이 될 수도 있다. 그를 파악하기 위해서는 전, 후 문장에서 단서가 필요하다. 그 단서를 통해 문맥 상황에서 '그'가 누군지 추론할 수 있다.
- 자바스크립트 세계관에서도 '그' 와 같은 개념이 this
라는 예약어이다.
- this
는 자바스크립트 엔진에 의해 암묵적으로 생성되기 때문에, 상황에 따라 가리키는 대상이 바뀔 수 있다.
즉, this는 문맥에 따라 그 의미(값)가 변경된다.
👨🏻💻 예시 코드
const name = 'something box';
function getBoxName() {
console.log(this.name);
}
const obj = {
name: 'moon',
box: getBoxName,
};
getBoxName(); // ?
obj.box(); // ?
line 12, 13 는 둘 다 getBoxName
이라는 동일한 함수를 실행시킨다. 하지만 그 결과는 다르게 찍힌다.
- line 12: getBoxName
이라는 일반 함수를 실행하였다. 이런 경우 this
는 전역 객체(=window)를 가리킨다.
- line 13: obj.box는 getBoxName을 참조하여, getBoxName를 실행시킨다. 하지만 obj.box의 형식으로 dot notation방식
으로 실행시킬 경우 obj
가 this로 바인딩된다.
즉, point는 "함수를 어디서 어떻게 실행하는가"
이다
→ 해당 함수를 실행시키는 부분을 찾아서 파악해야 한다.
(this를 이용하는) 함수를 실행하는 방법은 크게 4가지 경우
로 나눌 수 있다. 해당 함수가 어떤 방식으로 실행되느냐에 따라 this의 값이 바뀐다.
⚡️ 함수를 실행하는 4가지 방식
👉 1. 일반 함수 실행 방식
함수가 일반적인 방식으로 실행되면 전역 객체(=window)
function foo() {
console.log(this); // ?
}
foo(); // ?
- line2: 선언된 부분만 보고는 this가 무엇인지 절대 알 수 없다.
- line5: 일반 함수 방식으로 실행되었으므로, this는 전역 객체(=window)를 가리킨다.
'use strict' 모드
일 경우 this는 undefined
'use strict'
const name = 'ken';
function foo() {
console.log(this.name); // ?
}
foo(); // ?
- line1: use strict 모드 명시
- line6: use strict 모드이기 때문에 함수가 어떻게 실행되었는지 상관없이 this는 undefined
- line9: this는 undefined이고, undefined.name
이 되면서, Uncaught TypeError
발생
+ 추가: strict mode를 사용하는 이유
어떤 사람이 함수를 실행할 때 window
를 참조하기 위해 this 키워드를 사용하여 코드를 작성하였다. 하지만 다른 동료가 해당 함수를 메서드로 사용할 경우, dot Notation으로 접근 시 this는 다른 객체를 참조하게 되면서 의도하지 않은 결과를 발생시키게 된다. 이는 버그라고 볼 수 있다. 이런 경우 명시적으로 strict mode를 사용하여 this를 undefined로 만들어 이후 발생할 수 있는 예기치 못한 에러를 잡아주는 역할을 한다.
❗️QUIZ
var height = 180;
function bar() {
console.log(this.height);
}
function foo() {
var height = 150;
bar();
}
foo();
- strict mode가 아니다
- line4: bar 함수는 this 키워드 사용
- line9: 일반 함수 실행 방식으로 bar함수가 호출 → this는 window를 가리키고, window.height
인 180을 출력
👉 2. Dot Notation
Dot Notaion 방식으로 실행 시 this는 해당 객체를 참조
❗️QUIZ
var height = 150;
var person = {
height: 180,
foo: function foo() {
console.log(this.height);
}
};
person.foo();
- line9: foo 함수는 person 객체의 dot notation 방식
으로 실행 → this는 person 객체
- this가 person로 바인딩되기 때문에, window.height
가 아닌 person.height
를 참조
❗️QUIZ
function foo() {
console.log(this.height);
}
var height = 50;
var tony = {
height: 170,
foo: foo
};
var elon = {
height: 200,
foo: function () {
console.log(this.height);
}
};
tony.foo(); // ?
elon.foo(); // ?
- line 17, 18: 둘 다 dot notation 방식
으로 함수를 실행, foo 함수의 this는 각각 tony, elon을 바인딩
❗️QUIZ
var height = 100;
var tony = {
height: 170,
foo: function bar() {
console.log(this.height);
}
};
var elon = {
height: 200,
foo: tony.foo
};
var foo = tony.foo;
tony.foo(); // Q1
elon.foo(); // Q2
foo(); // Q3
- line 15, 16: 이전 퀴즈와 동일하게 this는 각각 tony, elon에 바인딩
- line 17: foo는 일반 함수 실행 방식, this는 window에 바인딩되므로 100이 출력
❗️QUIZ
👉 3. call, bind, apply
Function.prototype.call : 첫 번째 인자로 전달한 객체를 this에 바인딩하고,함수를 실행
Function.prototype.apply : 첫번째 인자로 전달한 객체를 this에 바인딩하고,함수를 실행
Function.prototype.bind : 첫번째 인자로 전달한 객체를 this에 바인딩하고,해당 함수를 반환
⇒ 함수 객체라면 프로토타입 체이닝을 통해 call, apply, bind 메서드를 사용할 수 있다.
var age = 100;
function foo() {
console.log(this.age);
}
var elon = {
age: 35
}
var tony = {
age: 31
}
foo(); // Q1 : window
foo.call(elon); // Q2 : ?
foo.apply(tony) // Q3 : ?
- Q1 :
- foo 함수가 일반 함수
실행, this는 window 객체
- Q2:
- foo.call
함수가 실행 인자로는 elon 객체가 전달
- 인자로 전달된 elon
객체가 foo함수의 this로 바인딩
- Q3
- foo.apply
함수가 실행 인자로는 elon 객체가 전달
- 인자로 전달된 tony
객체가 foo함수의 this로 바인딩
foo라는 함수를 실행할 건데call
혹은apply
를 통해
this로 바인딩할 객체를 첫 번째 인자로 명시적 전달할 수 있다.
call과 apply의 차이
var age = 100;
function foo(a, b, c, d, e) {
console.log(this.age);
console.log(arguments);
}
var tony = {
age: 35
};
foo.call(tony);
foo.apply(tony, [1, 2, 3, 4, 5]);
call과 apply의 차이는
foo 함수에서 사용할 두 번째 인자들(a, b, c, d, e)를 전달하는 방식에 있다. (1번 인자는 동일)
- call
- 1번 인자: this로 바인딩할 객체
- 2~n번 인자: 함수에서 arguments로 사용할 인자를 차례대로 전달
- apply
- 1번 인자: this로 바인딩 할 객체
- 2: 함수에서 arguments로 사용할 인자를 배열 형태
로 전달
❗️QUIZ
var age = 100;
function foo() {
console.log(this.age);
}
var tony = {
age: 35
}
var bar = foo.bind(tony);
bar(); // ?
- bar()
라는건, bar는 함수를 의미 ⇒ foo.bind
는 함수를 리턴
- foo.bind
함수의 인자로는 foo 함수에서 this로 바인딩할 객체를 전달하여 this를 명시적 바인딩
❗️QUIZ
var age = 100;
function foo() {
console.log(this.age);
console.log(arguments);
}
var elon = {
age: 34
}
var bar = foo.bind(elon);
bar(1, 2, 3, 4, 5); // ?
- foo.bind(elon): elon 객체를 this에 바인딩하고 해당 함수를 return
- bar(1, 2, 3, 4, 5) : 함수에 1, 2, 3, 4, 5 인자가 전달
👉 4. new 키워드
new 키워드로 함수를 호출할 경우 특정 과정으로 동작한다.
function foo(name, age) {
console.log(this);
return this;
}
console.log(foo()); // Q1
console.log(new foo()); // Q2
- Q1. 일반 함수 호출 방식이므로 this는 window 객체
- Q2. new 키워드
로 함수를 호출한 경우 아래 코드와 같은 내부 동작이 진행된다.
new 키워드의 내부 동작
function foo(name, age) {
this = {};
console.log(this);
this.name = name
this.age = age
this.__proto__ = foo.prototype
return this;
}
1. 새로운 빈객체 {}
를 생성하고 this는 이 객체를 참조한다.
2. 1에서 만든 빈 객체(this)
에 foo함수에서 인자로 받은 name, age를 property로 할당
3. 빈 객체(this)
에 __proto__
프로퍼티가 foo.prototype
를 가리키도록 한다. (프로토타입 체이닝
을 위해)
4. 최종적으로 this(생성한 객체)
를 리턴
즉new 키워드
로 함수 호출 시 this는 생성된 객체를 가리키고, 해당 함수를생성자 함수
라고 한다.
이는프로토타입
,프로토타입 체이닝
개념에 대한 이해가 필요한데, 자세한 내용은 아래 포스팅 참고
👉 + 화살표 함수(arrow function)
화살표 함수의 this는 일반 함수와 달리 상위 스코프의 this를 가리킨다.
let group = {
title: "1모둠",
students: ["보라", "호진", "지민"],
showList() {
this.students.forEach(function(student) {
alert(this.title + ': ' + student)
});
}
};
group.showList();
- line5: showList 함수는 dot notation 방식으로 실행, this는 group 객체
- line7: forEach에 인자로 전달된 함수는 일반 함수이므로 this는 window 객체
- 예상과 다르게 "undefined: 보라", "undefined: 호진", "undefined: 지민" 을 출력
let group = {
title: "1모둠",
students: ["보라", "호진", "지민"],
showList() {
this.students.forEach(student => alert(this.title + ': ' + student));
}
};
group.showList();
- forEach에 인자로 화살표 함수가 전달
- this.title은 화살표 함수 바깥에 있는 showList 메서드에서 this가 가리키는 대상(group 객체)과 동일해진다.
참고
- https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/this
- https://poiemaweb.com/js-this
- https://poiemaweb.com/es6-arrow-function
'프로그래밍 > JAVASCRIPT 사전' 카테고리의 다른 글
[JS] 모듈 import/export 문법 빠르게 정리하기 (0) | 2021.09.18 |
---|---|
[JS] scope 와 실행 컨텍스트 (0) | 2021.06.11 |
[JS] 화살표 함수, 쉽고 빠르게 정리하기 (8) | 2021.05.11 |
[YOU DON'T KNOW JS 정리] THIS (1) (4) | 2021.05.08 |
[JS] arguments 객체 그리고 유사배열 객체 (0) | 2021.05.05 |
댓글
이 글 공유하기
다른 글
-
[JS] 모듈 import/export 문법 빠르게 정리하기
[JS] 모듈 import/export 문법 빠르게 정리하기
2021.09.18 -
[JS] scope 와 실행 컨텍스트
[JS] scope 와 실행 컨텍스트
2021.06.11 -
[JS] 화살표 함수, 쉽고 빠르게 정리하기
[JS] 화살표 함수, 쉽고 빠르게 정리하기
2021.05.11 -
[YOU DON'T KNOW JS 정리] THIS (1)
[YOU DON'T KNOW JS 정리] THIS (1)
2021.05.08