1. 상황에 따라 달라지는 this
- 스크립트에서 this는 기본적으로 실행 컨텍스트가 생성될 때 함께 결정된다.
- 실행 컨텍스트는 함수를 호출할 때 생성되므로, 바꿔 말하면 this는 함수를 호출할 때 결정된다.
1-1) 전역 공간에서의 this
- 전역 공간에서 this는 전역 객체를 가리킨다.
- 전역 객체는 JS 런타임 환경에 따라 다른 이름과 정보를 가진다(브라우저=window, Node.js=global)
※전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로도 할당한다!?
- 전역공간에서 변수 a에 1을 할당하니 window.a(전역객체)와 this.a 모두 1로 출력된다.
- 이는 '전역변수를 선언하면 자바스크립트 엔진은 이를 전역객체의 프로퍼티로 할당한다'라는 공식 때문이다.
- 따라서 window(전역객체)의 프로퍼티로도 a가 할당되므로 window.a 가 1이 되는것이다.
- 이 말은 즉슨, window의 프로퍼티에 직접 할당하더라도 결과적으로 var로 선언한 것과 같이 동작한다 (단, 삭제 명령 시에는 동일하게 동작하지 않는데, 사용자의 의도치않은 삭제를 방지하는 차원에서 마련한 방어책이라고 한다)
1-2) 메서드로서 호출할 때 그 메서드 내부에서의 this
- 어떤 함수를 실행하는 방법 중 일반적인 두가지는 함수로서 호출하는 경우와 메서드로서 호출하는 경우이다.
- 두 개의 차이는 바로 독립성인데, 함수는 독립적으로 기능을 수행하지만, 메서드는 자신을 호출한 대상 객체에 관한 동작을 수행한다.
- ※메서드는 '객체의 프로퍼티에 할당된 함수'라는 말은 반은 맞고 반은 틀리다. 할당한다 해서 무조건 메서드가 되는것이 아니라 객체의 메서드로서 호출할 때만 메서드로 동작하고, 아니면 함수로 동작한다.
- 1번째 줄에서 func라는 변수의 익명함수를 할당했고, 4번째 줄에서 func를 호출했더니 this로 전역객체(window)가 출력된다
- 6번째 줄에서 변수에 객체를 할당했고, 그 객체 메서드 프로퍼티에 앞에서 만든 func 함수를 할당하고, 9번째 줄에서 obj의 메서드를 호출했더니, 이번엔 this가 obj라고 한다. obj.method와 func 모두 1번째 줄에서 선언한 func 함수를 참조하는데 말이다.
- 즉, 변수에 담아 호출한 경우와 obj 객체의 프로퍼티에 할당해서 호출한 경우 this가 다르다는 것이다.
- 그렇다면 '함수로서의 호출' 과 '메서드로서의 호출'을 구분하는 방법은 뭐냐? 함수앞에 점(.)의 유무 차이, 이게 끝이다
- 메서드 내부에서의 this는 호출한 주체에 대한 정보, 즉 함수명 앞의 객체이다.(obj.method)라면 method함수명 앞의 객체인 obj가 this라는 것이다.)
1-3) 함수로서 호출할 때 그 함수 내부에서의 this
- 함수 내부에서의 this는 정의 되지않는다. this에는 호출한 주체에 대한 정보가 담기는데, 함수로서 호출하는 것은 호출 주체를 명시하지 않고 개발자가 코드에 직접 관여해서 실행한 것이기 때문에 호출 정보를 알 수 없기 때문이다.
- this가 지정되지 않으면 전역 객체를 바라보므로 함수의 this는 전역객체가 되는 것이다.
- 그렇다면 함수에서의 this를 사용하려면? ES5까지는 변수 활용을 통해 우회해야했다.
- 하지만 ES6부턴 실행 컨텍스트를 생성할때 this 바인딩 과정 자체를 생략하는 화살표 함수를 도입하여 우회할 수 있게되었다.
1-4) 콜백 함수 호출 시 그 함수 내부에서의 this
- ※콜백함수란? 함수 A의 제어권을 다른 함수(또는 메서드) B에게 넘겨주는 경우 함수 A를 콜백 함수라 한다.
- 이때 함수 A는 함수 B의 내부 로직에 따라 실행되며, this 역시 함수 B 내부 로직에서 정한 규칙에 따라 결정된다.
- 콜백함수도 함수이기에 기본적으론 전역객체를 this로 삼지만, 제어권을 받은 함수에서 콜백 함수에 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조하게 된다.
1-5) 생성자 함수 내부에서의 this
- 생성자 함수의 this는 곧 새로 만들 구체적인 인스턴스 자신이다.
2. 명시적으로 this를 바인딩하는 방법
앞 절에서 상황별로 this에 어떤 값이 바인딩되는지를 살펴봤고
이번 절에선 이러한 규칙을 깨고 this에 별도의 대상을 바인딩 하는것을 알아본다
2-1) call 메서드
- call 메서드는 메서드의 호출 주체인 함수를 즉시 실행하도록 하는 명령이다.
- 이때 call 메서드의 첫번째 인자를 this로 바인딩하고, 그 뒤 인자들을 호출할 함수의 매개변수로 한다.
2-2) apply 메서드
- 기능적으로 call과 완전 동일하다.
- 두번째 인자로 배열을 받고 그 배열의 요소들을 함수의 매개변수로 사용한다는 차이만 존재
2-3) call / apply 메서드의 활용
- 마땅한 대안이 없던 ES5,6 버전 이전엔 실무에서 널리 통용되던 방법
위와 같이 call, apply를 활용하면 반복을 줄이고 효율을 높일 수 있다.
2-4) bind 메서드
- ES5에서 추가된 기능으로, call과 비슷하지만 즉시 호출하지는 않고 넘겨 받은 this 및 인수들을 바탕으로 새로운 함수를 반환하기만 하는 메서드이다
- 다시 새로운 함수를 호출할때 인수를 넘기면 앞서 bind 메서드에서 전달했던 인수들의 뒤에 등록된다.
- 즉, bind 메서드는 함수에 this를 미리 적용하는 것과 부분 적용 함수를 구현하는 것 두가지 목적을 가진다
위와 같이 bind 메서드를 사용해 this를 미리 적용할 수도, 함수의 {4,5} {6,7}을 구분해서 선언할 수도 있다.
※bind 메서드를 적용해 새로만든 함수는 name 프로퍼티에 bind의 수동태인 bound가 앞에 붙는다. 이 때문에 함수 추적에 call이나 apply보다 더 유용하다
2-5) 화살표 함수의 예외사항
- ES6에 새로 도입된 화살표 함수는 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외 되었다.
- 즉, 이 함수 내부에는 this가 아예 없으며, 접근하고자 하면 스코프체인 상 가장 가까운 this에 접근한다
코드 4번째에서 화살표함수로 선언했고 5번째 줄의 this는 존재하지 않으므로 스코프체인 상 가장 가까운 outer 함수의 this에 접근하게 된다!!
2-6) 별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)
- 다음장에서 자세히 다룬다고 한다
- 콜백 함수를 인자로 받는 메서드 중 일부는 추가로 this로 지정할 객체(thisArg)를 인자로 지정할 수 있는 경우가 있다.
- 이러한 메서드의 thisArgs 값을 지정하면 콜백 함수 내부에서 this 값을 원하는 대로 변경할 수 있다.
- 이러한 형태는 내부 요소에 대해 같은 동작을 반복 수행해야하는 배열 메서드에 많이 포진 돼 있으며, 같은 이유로 ES6에서 등장한 Set, Map 등의 메서드에서도 일부 존재한다.
'자바스크립트 > 코어 자바스크립트' 카테고리의 다른 글
코어자바스크립트 6장<프로토타입> (0) | 2022.08.18 |
---|---|
코어자바스크립트 5장<클로저> (0) | 2022.08.17 |
코어자바스크립트 4장<콜백 함수> (0) | 2022.08.14 |
코어자바스크립트 2장<실행 컨텍스트> (0) | 2022.08.12 |
코어자바스크립트 1장<데이터 타입> (0) | 2022.08.11 |