What is this?
👉 객체 지향 언어에서는 클래스로 생성한 인스턴스 객체
👉 자바스크립트에서는 어디서든 사용 가능. 함수와 객체(메서드)를 유일하게 구분 짓는 기준.
01. 상황에 따라 달라지는 this
👉 this는 실행컨텍스트가 생성될 때 결정됨. 즉 함수를 호출할 때 결정됨.
3-1-1. 전역 공간에서의 this
👉 브라우저 환경에서는 window, Node.js에서는 global
👉 전역 변수 선언 시 자바스크립트 엔진은 이를 전역 객체의 프로퍼티로 할당. 자바스크립트의 모든 변수는 실행 컨텍스트 LexicalEnvironment의 프로퍼티로서 동작.
👉 전역 공간에서 window의 프로퍼티에 직접 데이터를 할당하더라도 var로 변수 선언한 것과 똑같이 동작. 허나 '삭제' 명령은 다르게 동작.
👉 전역 객체의 프로퍼티로 할당한 경우에는 삭제되지만 전역 변수로 선언한 경우에는 삭제되지 않음.
3-1-2. 메서드로서 호출할 때 그 메서드 내부에서의 this
🥊 함수 vs 메서드
👉 둘의 차이점은 독립성. 함수는 그 자체로 독립적인 기능을 수행하는 반면, 메서드는 자신을 호출한 대상 객체에 관한 동작 수행.
👉 어떤 함수를 객체의 프로퍼티에 할당한다고 메서드가 되는 것이 아니라, 객체의 메서드로서 호출할 경우에만 메서드로 동작.
👉 4번째 줄 호출한 func의 this는 Window, 9번째 줄에서 호출한 obj의 method는 this로 obj 반환. 즉 익명 함수를 변수에 담아 호출한 경우와, 객체의 메서드로 호출한 경우 this가 달라짐.
👉 점(.) 표기법이든 대괄호([]) 표기법이든 함수 이름(프로퍼티명) 앞에 객체가 명시돼 있는 경우 메서드로 호출한 것.
💙 메서드 내부에서의 this
👉 this에는 마지막 점 앞에 명시된 객체에 대한 정보가 담김.
3-1-3. 함수로서 호출할 때 그 함수 내부에서의 this
💙 함수 내부에서의 this
👉 어떤 함수를 함수로서 호출하는 것은 객체지향 언어에서의 객체를 명시하지 않고 개발자가 코드에 직접 관여해서 실행한 것이기 때문에 함수에서의 this는 전역 객체를 가리킴.
💙 메서드의 내부함수에서의 this
👉 (1): obj1, (2): window, (3): obj2
👉 메서드의 내부함수 역시 함수를 호출할 때 함수 혹은 메서드로 호출했는지만 파악하면 this의 값을 정확히 알 수 있다. this 바인딩에 관해서는 오직 해당 함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지 없는지가 관건.
💙 메서드 내부 함수에서의 this를 우회하는 방법
👉 ES5까지는 주변 환경의 this를 그대로 상속받아 사용하려면 변수를 활용하여 이를 구현할 수 있음.
👉 위 예제 innerFunc1 내부에서 this는 전역 객체를 가리킴. innerFunc2 내부에서는 outer 스코프의 this를 할당한 self라는 변수를 호출했기 때문에 객체 obj가 this로서 출력됨.
💙 this를 바인딩하지 않는 함수
👉 ES6에서는 함수 내부에서 this가 전역객체를 바라보는 문제를 보완하고자 this를 바인딩하지 않는 화살표 함수(arrow function)을 새로 도입.
3-1-4. 콜백 함수 호출 시 그 내부에서의 this
🤔 콜백 함수?
❕ 함수 A의 제어권을 다른 함수 또는 메서드 B에게 넘겨주는 경우 함수 A를 콜백 함수라고 함.
👉 콜백 함수도 기본적으로 함수이기 때문에 this가 전역객체를 참조하지만 콜백 함수는 제어권을 가진 함수의 내부로직에 따라 실행되므로 제어권을 가진 함수에서 별도로 this가 될 대상을 지정한 경우에는 그 대상을 참조.
👉 (1) setTimeout 함수와, (2) forEach메서드는 따로 this를 지정하지 않았으므로 콜백 함수 내부의 this는 전역 객체를 참조함. (3) addEventListener 메서드는 콜백 함수를 호출할 때 자신의 this를 상속하므로 this는 점(.) 앞의 요소가 가 됨.
3-1-5. 생성자 함수 내부에서의 this
🤔 생성자 함수?
❕ 공통된 성질을 지니는 객체들을 생성하는 데 사용하는 함수. 객체지향 언어에서는 생성자를 클래스(class), 클래스로 만든 객체를 인스턴스(instance)라고 함.
👉 생성자는 구체적인 인스턴스를 만들기 위한 틀. 틀에는 해당 클래스의 공통 속성들이 준비돼 있고 여기에 각 인스턴스의 개성을 더해 개별 인스턴스 생성.
👉 자바스크립트에서 new 명령어와 함께 함수를 호출하면 해당 함수는 생성자로서도 동작함. 생성자로 호출된 함수 내부의 this는 새로 만들 구체적인 인스턴스 자신이 됨.
👉 생성자 함수를 호출하면 생성자의 prototype 프로퍼티를 참조하는 __proto__라는 프로퍼티가 있는 객체(인스턴스)를 만들고 미리 준비된 공통 속성 및 개성을 해당 객체(this)에 부여함.
👉 6, 7번째 줄에서 Cat이라는 생성자 함수를 만들어 각각 choco, nabi라는 변수에 할당. 8번째 줄에서 두 변수를 출력해보니 두 함수 내부의 this 모두 각각의 인스턴스를 가리킴을 알 수 있음.
02. 명시적으로 this를 바인딩하는 방법
3-2-1. call 메서드
👉 메서드의 호출 주체인 함수를 즉시 실행하는 명령.
👉 첫 번째 인자를 this로 바인딩, 이후 인자들을 호출할 함수의 매개변수로 할당.
3-2-2. apply 메서드
👉 call 메서드와 기능적으로 완전히 동일. 두 번째 인자를 배열로 받고 그 요소들을 호출할 함수의 매개변수로 할당.
3-2-3. call / apply 메서드의 활용
💙 유사배열객체(array-like object)에 배열 메서드를 적용
👉 객체 내 프로퍼티의 키 및 length 프로퍼티의 값이 0 또는 양의 정수일 때를 유사배열객체라고 함.
👉 유사배열객체에는 call 또는 apply 메서드를 이용해 모든 배열 메서드를 차용 가능.
👉 함수 내부에서 접근하는 arguments 객체, querySelectorAll, getElementsByCalssName 등의 Node 선택자로 선택한 결과인 NodeList도 마찬가지로 활용 가능.
👉 문자열은 length 프로퍼티가 읽기 전용이기 때문에 원본 문자열에 변경을 가하는 메서드(push, pop, shift, unshift, splice 등)는 사용 불가이고 concat처럼 대상이 반드시 배열이어야 하는 메서드는 error를 반환.
⛔ call / apply 메서드를 형변환에 이용하는 것은 'this를 원하는 값으로 지정해서 호출'한다는 본래의 메서드 활용법과 동떨어짐. 따라서 ES6에서는 유사배열객체 또는 순회 가능한 모든 데이터 타입을 배열로 전환하는 Array.from 메서드를 새로 도입.
💙 생성자 내부에서 다른 생성자를 호출
👉 생성자 내부에 다른 생성자와 공통된 내용이 있다면 call 또는 apply 메서드를 호출하여 반복을 줄일 수 있음.
💙 여러 인수를 묶어 하나의 배열로 전달하고 싶을 때 - apply 활용
👉 apply를 사용하지 않고 최대값, 최솟값을 구하려고 하면 위와 같이 복잡함. 아래와 같이 Math.max/Math.min 메서드에 apply를 적용하거나 ES6의 펼치기 연산자(spread operator)를 쓰면 훨씬 간단함.
3-2-4. bind 메서드
👉 bind메서드는 ES5에서 추가된 기능으로 call과 비슷하지만 즉시 호출하지는 않고 넘겨 받은 this 및 인수들을 바탕으로 새로운 함수를 반환만 하는 메서드임. 새로운 함수를 호출할 대 인수를 넘기면 그 인수들은 기존 bind 메서드를 호출할 대 전달했던 인수들의 뒤에 이어서 등록됨. bind 메서드는 함수에 this를 미리 적용하거나 부분 적용 함수를 구현하는 두 가지 목적을 지님.
👉 6번째 줄의 bind는 this를 미리 적용한 예이고 9번째 줄의 bind는 this 지정과 함께 부분 적용 함수를 구현한 예.
💙 name 프로퍼티
👉 bind 메서드를 적용해서 새로 만든 함수의 name 프로퍼티에는 'bound'라는 접두어가 붙음.
💙 상위 컨텍스트의 this를 내부함수나 콜백 함수에 전달하기
👉 call, apply, bind 등 메서드를 이용하면 내부함수 및 콜백 함수 내에서 this에 관여하는 함수 또는 메서드에 대해서도 this를 그대로 바라보게 할 수 있음.
3-2-5. 화살표 함수의 예외사항
👉 ES6에서 도입된 화살표 함수는 실행 컨텍스트 생성 시 this를 바인딩하는 과정이 제외됨. 즉 화살표 함수 내부에는 this가 전혀 없고 스코프체인상 가장 가까운 this에 접근함.
3-2-6. 별도의 인자로 this를 받는 경우(콜백 함수 내에서의 this)
👉 콜백 함수를 인자로 받는 메서드 중에는 this로 지정할 객체(thisArg)를 인자로 지정하여 콜백 함수 내부에서 this 값을 원하는 대로 변경할 수 있는 게 있음. 주로 배열 메서드에 많음.
👉 9번째 줄에서 forEach 메서드 콜백 함수 내부의 this를 바인딩했으므로 this는 add 메서드의 this(report)를 그대로 가리킴.
03. 정리
💫 명시적 this 바인딩이 없는 경우
- 전역공간에서 this는 전역객체(브라우저: window, Node.js: global) 참조.
- 어떤 함수를 메서드로서 호출한 경우 this는 메서드 호출 주체(메서드명 앞의 객체)를 참조.
- 어떤 함수를 함수로서 호출한 경우 this는 전역객체를 참조. 메서드 내부함수도 동일.
- 콜백 함수 내부에서 this는 해당 콜백함수의 제어권을 가진 함수가 정의한 바에 따르며, 정의하지 않으면 전역객체 참조.
- 생성자 함수의 this는 생성될 인스턴스를 참조.
💫 명시적 this 바인딩이 있는 경우
- call, apply 메서드는 this를 명시적으로 지정하면서 함수 또는 메서드를 호출.
- bind 메서드는 this 및 함수에 넘길 인수를 일부 지정해서 새로운 함수를 만듦.
- 요소를 순회하면서 콜백 함수를 반복 호출하는 일부 메서드(배열 메서드 등)는 별도의 인자로 this를 받기도 함.
'👩💻 Programming > JavaScript' 카테고리의 다른 글
[코어 자바스크립트] 4장 콜백 함수 (0) | 2022.11.25 |
---|---|
[모던 자바스크립트 Deep Dive] 비동기 프로그래밍 (0) | 2022.11.20 |
코어 자바스크립트_2장 실행 컨텍스트 (0) | 2022.10.26 |
코어 자바스크립트_1장 데이터 타입 (0) | 2022.10.24 |
[JavaScript] SNS 공유하기 (카카오, 라인, 트위터, 페이스북) (0) | 2022.10.15 |
댓글