You don't Know JS - This
Chapter 1 This or That?
JS에서 가장 헷갈리는 키워드인 this에 대해서 알아보자.
this
는 런타임 바인딩. 즉 함수가 호출될 때 바인딩이 결정된다.this
를 호출과 무관하게 고정시킬 수 있는 것이bind
함수를 호출할 때마다 함수 컨텍스트가 생기는데, 컨텍스트 내에 변수객체, 스코프체인, this가 생성된다.
함수호출방식에 따라 바인딩되는 객체가 달라진다.
-1. 컨텍스트
스코프 호이스팅 this, 클로저 등의 동작원리를 담는 JS의 핵심원리이며
ECMAScript 스펙에선 "실행 가능한 코드를 형상화하고 구분하는 추상적인 개념"이라고 정의함.
실행 가능한 코드가 실행되기 위해 필요한 "환경"이라고 풀어쓸 수 있음.
-1.1 컨텍스트 종류와 생성순서
컨텍스트 종류는 다음과 같다
컨텍스트 종류
- 함수가 실행될때마다 생성되는 함수컨텍스트
- 코드가 실행되면 생기는 전역컨텍스트
코드가 실행되는 순간 컨텍스트가 생성이 되는데 종류에는 전역
, 함수
컨텍스트가 있음. 이 컨텍스트가 생성되면 그 안에 생기는 것들도 있는데 다음과 같다.
컨텍스트 생성시 생성되는 것들
- 변수객체
- scope chain
- this
컨텍스트가 생성되고 함수가 실행되면 함수안에 사용되는 변수들은 첫번째로, 변수객체안에서 값을 찾고, 없으면 스코프체인을 따라 올라가면서 변수를 찾는다.
함수가 끝나면 해당 컨텍스트는 사라진다 (클로저 제외)
페이지가 종료되면 전역 컨텍스트는 사라진다.
var name = 'zero'; // (1)변수 선언 (6)변수 대입
function wow(word) { // (2)변수 선언 (3)변수 대입
console.log(word + ' ' + name); // (11)
}
function say () { // (4)변수 선언 (5)변수 대입
var name = 'nero'; // (8)
console.log(name); // (9)
wow('hello'); // (10)
}
say(); // (7)
10번에서 wow()
가 호출되었을 때 스코프체인이 say()
가 아닌 전역객체
인이유?
함수가 중첩된 경우가 아니다 (함수안에 함수선언이 아님)
wow()
는 전역에 선언되어있으므로 선언 당시에 이미 전역에 스코프체이닝이 되어있음함수가 어디서 호출 되었는지, 어디서 선언 되었는지에 따라 상위 스코프를 결정할 수 있음
- 어디서 호출 : 동적 스코프
- 어디서 선언 : 렉시컬 스코프
0. 바인딩
- 어떤 함수를 호출할 때 그 함수가 위치한 메모리번지에 연결시켜주는 것을 의미함.
- JS에서 함수 호출 시 암묵적으로 argument, this가 전달된다. 어디서 호출되는지에 따라 전달되는
this
값이 달라져서 우리가 헷갈리는 것.
1. This
this는 객체 자신에 대한 참조값을 갖고 있는데, JS에서는 이 참조값이 자신이 아닌 함수호출방식에 따라 결정되는 것
- 모든 함수 스코프내에 자동으로 설정되는 특수한 식별자. (함수컨텍스트 생성시 포함.)
- 메소드를 호출한 객체가 저장되어있는 속성 (함수호출방식에 따라 바인딩할 객체가 동적으로 결정.)
- this의 값은 함수를 호출한 방법이 결정합니다
- this 키워드는 다른 컨텍스트에서 함수를 재사용할 수 있게 한다. 다르게 말하면, this 키워드는 함수나 메소드가 호출될 때 어떤 object 에 초점을 맞출 것인지 결정할 수 있게 한다.
함수호출 방식은 4가지가 있다.
아래에 대한 자세한 예시는 맨 밑 this 예시 2
출처에서 참고하도록 하자.
- 함수 호출
- 메소드 호출
- 생성자함수 호출
- apply / call / bind 호출
1. 함수호출
- 내부함수(중첩)는 일반함수, 메소드, 콜백함수 상관없이 this는 전역객체를 바인딩 한다 (설계 단계의 결함..)
전역객체참조를 피하기 위한 방법
내부함수의
this
가 전역객체 참조를 피하기 위해선that
을 사용한다.that
에 자신을 호출한 객체의 참조값을 넣는다.명시적 바인딩인
apply, call, bind
메소드 사용 예제참조
2. 메소드 호출
this
는 메소드를 소유한 객체, 즉, 해당 메소드를 호출한 객체에 바인딩된다. 예제참조
3. 생성자 함수 호출
JS의 생성자는 기존함수에 new
연산자를 붙여 호출하면 생성자함수로 동작한다.
4. 명시적 바인딩
apply, call, bind은 this를 명시적으로 바인딩할 수 있는 메소드.