This
- This
- 키워드
- obj.name() 형태로 호출한 함수(메소드)에서 this로 인스턴스(오브젝트)를 참조
- 실행 콘텍스트의 this 바인팅 컴포넌트(TBC)에 바인딩
- This와 글로벌 오브젝트
- 글로벌 오브젝트에서 this는 글로벌 오브젝트를 참조한다
- 글로벌 함수를 참조할 때에 글로벌 오브젝트를 사용해서 호출할 수 없다.
- 묵시적으로 this를 사용하여 글로벌 오브젝트를 참조하도록 한다.
- this와 window 오브젝트
- window는 JS에서 만드는 것이 아니며 글로벌 오브젝트의 스코프도 아니다
- 하지만 window와 글로벌 오브젝트를 같은 선상에서 사용
- Host 오브젝트 개념을 적용하였기 때문이다.
window.onload = function() {}; console.log(this == window); // true var value = 100; console.log(this.value); // 100 console.log(window.value); // 100 this.value = 150; console.log(window.value); // 150
- window.onload = function() {};
- 글로벌 오브젝트에 코드 작성
- console.log(this == window); // true
- this가 window 참조
- var value = 100; console.log(this.value); // 100
- this가 글로벌 오브젝트를 참조하므로 this.value를 사용하여 변수 사용 가능
- console.log(window.value); // 100
- window가 글로벌 오브젝트를 참조하므로 window.value를 사용하여 변수 사용 가능
- this.value = 150; console.log(window.value); // 150
- this가 글로벌 오브젝트를 참조하므로 글로벌 오브젝트에 설정된다.
- window가 글로벌 오브젝트를 참조하므로 value를 사용할 수 있다.
- window 오브젝트와 같이 다른 오브젝트를 마치 내것 처럼 사용하는 개념을 Host 오브젝트라고 한다. DOM 오브젝트도 Host 오브젝트이다.
window.onload = function() { console.log(this === window); // true var value = 100; console.log(this.value); // undefined this.value = 100; console.log(window.value); // 100 };
- console.log(this === window); // true
- true가 출력된 것은 타입이 같다는 것
- this가 window를 참조하는 것은 window.onload = function() {…}에서 onload()가 window의 핸들러 함수이기 때문
- onload가 실행되며 window EC을 생성하고 해당 값을 TBC에 해당하기 때문에 this === window가 true
- var value = 100; console.log(this.value); // undefined
- this로 로컬(지역) 변수 사용
- value는 핸들러 함수(onload)의 지역 변수이다.
- this 가 window 오브젝트를 참조하므로 this.value 로 지역 변수에 악세스할 수 없다.
- console.log(window.value); // 100
- this가 window 오브젝트를 참조하기 때문에 window 오브젝트에 설정된다.
- window.onload = function() {};
- 글로벌 오브젝트에서 this는 글로벌 오브젝트를 참조한다
- This 참조 범위
- this와 strict 모드
- 오브젝트.함수이름() 형태로 함수 호출
- 글로벌 오브젝트는 오브젝트 이름이 없으므로 함수 이름만 작성하여 호출
- strict 모드에서는
- window.book()처럼 book()앞에 window를 글로벌 오브젝트로 작성
- 함수 앞에 오브젝트를 작성하지 않으면 TBC에 undefined가 설정되므로 this로 window를 참조할 수 없다.
function book() { "use strict"; return this; } var result = book(); console.log(result); // undefined var obj = window.book(); console.log(obj === window); // true
- var result = book();
- 호출하는 book() 함수 앞에 오브젝트를 작성하지 않으면 return this에서 undefined 반환
- TBC에 undefined가 설정되어 있기 때문
- var obj = window.book();
- 호출하는 book() 함수 앞에 window 오브젝트 작성, book() 함수가 글로벌 함수이므로 호출되며 return this에서 window 오브젝트 반환
- var result = book();
- 오브젝트.함수이름() 형태로 함수 호출
- this 참조 오브젝트
var book = { point: 100, get: function() { console.log(this === book); // true console.log(this.point); // 100 }, member: { point: 200, get: function() { console.log(this === book.member); // true console.log(this.point); // 200 } } } book.get(); book.member.get();
- this가 참조하는 오브젝트
- 마지막 줄에서 book.member.get() 호출
- this가 member 오브젝트 참조
- book은 get()을 호출하는 경로 역할
- console.log(this === book.member);
- TBC에 book.member 오브젝트가 설정. this가 book.member 를 참조하기 때문
- console.log(this.point);
- this가 book.member를 참조하므로 book.point값인 100을 출력하지 않고 book.member.point 200을 출력
- this와 strict 모드
- 정리 예제 1.
var book = { value: 123, get: function() { var value = 456; console.log(this === window); // true console.log(this.value); // undefined } } var fn = book.get; fn();
- fn()
- fn을 호출 할 때 참조하는 오브젝트가 없으므로 window를 참조한다.
- console.log(this === window);
- this가 window를 참조하기 때문에 true
- console.log(this.value);
- window 오브젝트 내에 value 값이 존재하지 않으므로 undefined
- fn()
- 정리 예제 2.
function getTitle() { console.log("HTML 책"); } var book = function() { function getTitle() { console.log("JS 책"); } this.getTitle(); // HTML 책 getTitle(); // JS 책 } book();
- book() 호출
- book은 윈도우 오브젝트를 참조하기 때문에 this 또한 윈도우 오브젝트를 참조한다.
- this.getTitle()
- 현재 this가 윈도우 오브젝트를 참조하고 있기 때문에 밖에 있는 getTitle()을 호출한다.
- getTitle()
- 참조하고 있는 오브젝트가 없기 때문에 현재 스코프에 있는 getTitle()을 호출한다.
- book() 호출
- this와 인스턴스
- 인스턴스 목적
- 인스턴스마다 고유 값 유지
- 인스턴스에서 this의 목적?
- this로 인스턴스를 참조하여 this.name 형태로 프로퍼티에 접근
- __proto__ 프로퍼티 접근
- prototype에 연결된 프로퍼티가 인스턴스의 __proto__에 첨부되며 this.method() 형태로 __proto__에 첨부된 method() 호출
var book = {}; book.Point = function(point) { this.point = point; }; // 생성자 book.Point.prototype.getPoint = function() { console.log(this.point); }; var obj = new book.Point(100); obj.getPoint(); // 100
- var obj = new book.Point(100);
- book.Point 인스턴스를 생성
- this.point = point;
- this가 생성한 인스턴스를 참조하므로 point는 인스턴스 프로퍼티가 된다.
- 이 논리는 인스턴스마다 프로퍼티 이름과 값을 유지할 수 있다.
- obj.getPoint();
- obj 인스턴스의 getPoint() 메소드 호출
- console.log(this.point);
- obj.getPoint()로 호출, this가 obj 참조
- obj는 book.Point 인스턴스
- book.Point 인스턴스의 point 값 출력
- 인스턴스 목적
-
this와 call()
구분 타입 데이터(값) Object Function 호출할 함수 이름 파라미터 object this로 참조할 오브젝트 파라미터 any 파라미터opt. 콤마로 구분, 다수 작성 가능 반환 any 호출된 함수에서 반환한 값 - getTotal.call(this,10, 20)
- 10과 20을 파라미터 값으로 넘겨줍니다.
- 첫 번째는 파라미터 값으로 넘어가지 않고 두 번째부터 넘어갑니다.
- 첫 번째 파라미터에 호출된 함수에서 this로 참조할 오브젝트 작성, this 이외에 다른 오브젝트 사용 가능
- 첫 번째 파라미터가 TBC에 바인딩된다.
window.onload = function() {}; "use strict"; var value = 100; function get(param) { return param + this.value; }; var result = get.call(this, 20); console.log(result); // 120
- window.onload 밖에 코드를 작성한다.
- 글로벌 오브젝트에서 실행한다.
- get.call(this, 20)
- 첫 번째 파라미터에 this 작성(글로벌 오브젝트)
- return param + this.value;
- this가 글로벌 오브젝트를 참조하므로 var value = 100;에 값을 사용한다.
- call 메서드를 사용하지 않고 get(20);을 하는 경우
- strict 모드이고, get에 오브젝트를 명시하지 않았기 때문에 this는 undefined이다.
- 에러가 발생한다.
- window.onload 밖에 코드를 작성한다.
- Object 사용
var get = function(value) { return this.base * this.rate + value; }; var value= { base: 20, rate: 30 }; var result = get.call(value, 50); console.log(result); // 650
- var result = get.call(value, 50);
- call()의 첫 번째에 Object 작성, 50은 파라미터 값
- return this.base * this.rate + value;
- call 메서드에 첫 번째 Object가 this로 바인딩 되므로 {base: 20, rate: 30}가 된다.
- this로 참조할 오브젝트를 변경할 수 있는 것이 call()의 특징
- var result = get.call(value, 50);
- 숫자 작성
function get() { return this.valueOf(); } var result = get.call(123); console.log(result); // 123
- var result = get.call(123);
- this가 오브젝트를 참조하므로 숫자(123)을 작성하면 에러가 발생해야 하지만
- 값(123) 타입에 해당하는 Number 인스턴스를 생성하고 123을 primitive 값으로 설정합니다.
- this가 Number 인스턴스를 참조합니다.
- var result = get.call(123);
- this 참조 변경
var book = { value: 123, point: { value: 456, get: function() { console.log(this.value); } } } book.point.get.call(book.point); // 456 book.point.get.call(book); // 123
- book.point.get.call(book);
- book.point의 get()을 호출
- get()의 this 객체를 book을 참조했기 때문에 this.value의 value는 book의 value로 123 출력
- book.point.get.call(book.point);
- book.point의 get() 호출
- get()의 this 객체를 book.point를 참조했기 때문에 this.value의 value는 book.point의 value로 456 출력
- book.point.get.call(book);
- getTotal.call(this,10, 20)
-
this 와 apply()
구분 타입 데이터(값) Object Function 호출할 함수 이름 파라미터 object this로 참조할 오브젝트 파라미터 any 파라미터opt 반환 any 호출된 함수에서 반환한 값 - getTotal.apply(this, [10, 20])
- 함수 호출 방법은 call()과 같으며 파라미터가 배열인 것이 다르다.
- [10, 20]을 파라미터 값으로 넘겨 준다.
- apply()는 두 번째 파라미터 수가 유동적일 때 사용하며, call()은 파라미터 수가 고정일 때 사용한다.
var obj= { 0: 10, 1: 20, 2: 30}; var data= [4, 5, 6]; function get() { for( k = 0; k < arguments.length; k++){ console.log(arguments[k] + this[k]); } } get.apply(obj, data); // 14, 25, 26 출력
- get.apply(obj, data);
- get() 함수에서 obj를 this로 참조
- 두 번째 파라미터 [4, 5, 6]을 arguments로 사용하여 계산, 파라미터 수가 유동적이므로 arguments가 편리
- get()의 함수 코드는 바뀌지 않으며 넘겨 주는 파라미터 값과 this로 참조할 오브젝트만 변경하면 된다.
- array-like 형태
- get.apply(obj, data);
- call 함수와 apply 함수를 사용하는 이유는 참조할 객체와 데이터가 변경되더라도 재사용 가능하도록 설계 및 구현하기 위해서이다.
- getTotal.apply(this, [10, 20])
- this와 콜백 함수
var obj = { value: 100 }; var data = [5, 6, 7]; function callback(element, index, data) { console.log(element); console.log(index); console.log(data); return element + this.value; } function get(data) { return data.map(callback, obj); } var result = get(data); console.log(result); // [105, 106, 107]
- ES5의 map(), forEach()처럼 콜백 함수가 있는 메서드는 두 번째 파라미터에 this로 참조할 오브젝트를 작성(option)
- ES5에는 콜백 함수를 사용하는 메서드가 7가지 있다.
- function callback(element, index, data) { return element + this.value; }
- map() 에서 호출하는 콜백 함수
- data는 map에 넘기는 전체 배열, index는 map의 순서(인덱스), element는 data의 index번째 값
- return data.map(callback, obj);
- map()의 두 번째 파라미터에 obj를 작성
- callback()에서 obj를 this로 참조
- map과 callback은 독립되어 있다. map은 데이터를 넘겨주는 것이 목적이고, 호출된 callback 함수는 값을 처리하는 역할을 한다.
- map()의 코드는 바꾸지 않고
- obj값과 data 파라미터 값만 바꾸면 된다.
- ES5의 map(), forEach()처럼 콜백 함수가 있는 메서드는 두 번째 파라미터에 this로 참조할 오브젝트를 작성(option)
- this와 bind()
-
bind() |구분|타입|데이터(값)| |:—|:—|:—| |Object|Function|호출할 함수 이름| |파라미터|object|this로 참조할 오브젝트| |파라미터|any|파라미터opt| |반환|any|호출된 함수에서 반환한 값|
- 두 번에 나누어 처리
- function 오브젝트 생성
- 생성한 function object를 함수로 호출
- 파라미터
- 1번째 파라미터에 함수에서 this로 참조할 오브젝트
- 2번째 파라미터에 호출된 함수의 파라미터 값
- 생성한 function을 호출할 때에도 파라미터 작성 가능
- 두개의 파라미터를 병합하여 사용
- 두 번에 나누어 처리
- function object 생성, 호출
var book = { point: 123, get: function() { return this.point; } }; var obj = book.get.bind(book); console.log(typeof obj); // function var result = obj(); console.log(result); // 123
- var object = book.get.bind(book);
- book.get()을 호출하지 않고 function object를 생성하여 반환
- 생성한 function object를 생성한 오브젝트의 [[TargetFunction]]에 설정
- 처리를 나누어서 하므로 저장 필요
- console.log(typeof obj);
- obj의 타입은 function object
- bind()의 첫 번째 파라미터
- get() 함수에서 this로 참조할 오브젝트 작성
- get() 앞에 작성한 오브젝트를 this로 참조하지 않음
- 작성하지 않으면 undefined로 설정
- 생성한 function 오브젝트의 [[BoundThis]]에 설정
- var result = obj();
- bind()로 생성한 function object 호출
- book.get() 함수가 호출된다.
- return this.point;
- this가 [[BoundThis]]를 참조
- 즉, book 오브젝트를 참조하므로 123 반환
- var object = book.get.bind(book);
- 파라미터 합
var book = { get: function() { return Array.prototype.slice.call(arguments); } } var obj = book.get.bind(this, 10, 20); var result = obj(30, 40); console.log(result); // 10, 20, 30, 40
- var obj = book.get.bind(this, 10, 20);
- 두번째, 세번째 파라미터에 값을 작성했으며 book.get()의 파라미터 값으로 넘겨준다.
- function object의 [[BoundArguments]]에 설정
- return Array.prototype.slice.call(arguments);
- get() 함수에 파라미터 이름을 작성하지 않고 arguments 사용
- slice()는 인덱스 범위의 엘리먼트를 배열로 반환
- 인덱스를 작성하지 않으면 arguments 전체 반환
- var result = obj(30, 40);
- book.get() 함수가 호출되며 book.get.bind(this, 10, 20); 에서 10과 20을 [10, 20] 배열 형태로 반환
- 여기에 obj(30, 40)의 30과 40을 병합(첨부)하여 반환
- var obj = book.get.bind(this, 10, 20);
- bind() 활용, 이벤트 처리
<script src="point.js" defer></script> <button id="point">값 출력</button>
var book = { myPoint: 100, setEvent: function() { // 이벤트 설정 var node = document.getElementById('point'); node.onclick = this.show.bind(book, node); }, show: function(node, event) { // 핸들러 함수 console.log(node.textContent); console.log(this.myPoint); } }; book.setEvent(); // 값 출력, 100
- 시나리오: 값 출력 버튼을 클릭하면 값을 표시합니다.
- 이벤트 처리의 어려움은 이벤트를 설정할 때의 오브젝트를 핸들러에서 this로 참조할 수 없다는 것
- bind()로 해결할 수 있다.
- document.getElementById(‘point’);
- button#point로 엘리먼트 오브젝트 생성
- node.onclick = this.show.bind(book, node);
- show()는 onclick 이벤트의 핸들러
- show()는 this로 book object를 참조하기 위해 바인드
- show() 파라미터 값으로 node를 넘겨준다.
- show: function(node, event) { … }
- button#point를 클릭했을 때 호출
- node: 이벤트를 설정한 엘리먼트
- event: Event 오브젝트
- console.log(this.myPoint);
- bind() 첫번째 파라미터에 book 오브젝트를 작성했으며 이를 this로 참조하므로 123이 표시된다.
-
** 출처1. 인프런 강좌_자바스크립트 중고급: 근본 핵심 이해