[자바스크립트 중고급] 6. this

Speedwell🍀·2022년 2월 1일
0

this 개요

  • 키워드

  • obj.name() 형태로 호출한 함수(메소드)에서 this로 인스턴스(오브젝트)를 참조

  • 실행 콘텍스트의 this 바인딩 컴포넌트에 바인딩


this와 글로벌 오브젝트

  • 글로벌 오브젝트에서 this는 글로벌 오브젝트 참조

  • this와 window 오브젝트

    • window는 JS에서 만든 것이 아니며 글로벌 오브젝트의 스코프도 아님
    • window와 글로벌 오브젝트를 같은 선상에서 사용
  • Hosw 오브젝트 개념 적용

  • 글로벌 오브젝트에 코드 작성
    window.onload = function(){
    // 안이 아니라 밖에 코드 작성
    };

  • this가 window 참조

log(this === window);

// true
  • this로 글로벌 변수 사용
var value = 100;
log(this.value);

// 100
  • window로 글로벌 변수 사용
var value = 100;
log(window.value);

// 100
  • this.value = 100; 형태로 값 할당
this.value = 100;
log(window.value);

// 100

this와 window 오브젝트

  • window.onload = function(){
    // 여기에 코드 작성
    }

  • this가 window 참조

window.onload = function(){
  log(this === window);
};

// true
  • this로 로컬(지역) 변수 사용
window.onload = function(){
  var value = 100;
  log(this.value);
};

// undefined
  • this.value = 100; 형태로 값 할당
window.onload = funciton(){
  this.value = 100;
  log(window.value);
};

// 100

this 참조 범위

this와 strict 모드

  • 오브젝트.함수이름() 형태로 함수 호출

    • 글로벌 오브젝트는 오브젝트 이름이 없으므로 함수 이름만 작성하여 호출
  • strict 모드에서는

    • window.book()처럼 book() 앞에 window를 글로벌 오브젝트로 작성
  • 함수 앞에 오브젝트를 작성하지 않으면

    • this 바인딩 컴포넌트에 undefined가 설정되므로
    • this로 window를 참조할 수 없음
function book(){
  "use strict";
  return this;
};
var result = book();
log(result);

// undefined
function book(){
  "use strict";
  return this;
};
var obj = window.book();
log(obj === window);

// true

this 참조 오브젝트

var book = {
  point: 100,
  memeber: {
    point: 200,
    get: function(){
      log(this === book.memeber);
      log(this.poin);
    }
  }
};
book.memeber.get();

// true
// 200
  • this가 참조하는 오브젝트

  • 마지막 줄에서 book.memeber.get() 호출

    • this가 member 오브젝트 참조
    • book은 get()을 호출하는 경로 역할
  • console.log(this === book.memeber);

    • [실행 결과]에 true가 출력되며 this가 book.member를 참조하기 때문
    • 즉, thiw 바인딩 컴포넌트에 book.memeber 오브젝트가 설정됨
  • console.log(this.point);

    • this가 book.memeber를 참조하므로
    • book.point 값인 100을 출력하지 않고 book.member의 200을 출력

정리 시간

var book = {
  value: 123,
  get: function() {
    var value = 456;
    log(this === window);
    log(this.value);
  }
};
var fn = book.get;
fn();

// true
// undefined
  • 마지막 줄에서 fn()을 호출하면 book.get() 함수가 호출됨

  • console.log(this === window)에서 true가 출력되는 논리를 제시하시오.

  • console.log(this.value)에서 undefined가 출력되는 논리를 제시하시오.


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(){
  log(this.point);
};
var obj = new book.Point(100);
obj.getPoint();

// 100
  1. var obj = new book.Point(100);

    • book.Point 인스턴스를 생성
  2. this.point = point;

    • this가 생성한 인스턴스를 참조하므로 point는 인스턴스 프로퍼티가 됨
    • 이 논리로 인스턴스마다 프로퍼티 이름과 값을 유지할 수 있음
  3. obj.getPoint();

    • obj 인스턴스의 getPoint() 메소드 호출
  4. console.log(this.point);

    • obj.getPoint()로 호출, this가 obj 참조
    • obj는 book.Point 인스턴스
    • book.Point 인스턴스의 point 값 출력

this와 call()

  • getTotal.call(this, 10, 20)

    • 10과 20을 파라미터 값으로 넘겨줌
    • 첫 번째는 파라미터 값으로 넘어가지 않고 두 번째부터 넘어감
  • 첫 번째 파라미터에

    • 호출된 함수에서 this로 참조할 오브젝트 작성
    • this 이외에 다른 오브젝트 사용 가능

this 사용

"use strict";
var value = 100;
function get(param){
  return param + this.value;
};
var result = get.call(this, 20);
log(result);

// 120
  • window.onload = function(){
    // onload 밖에 코드를 작성
    // 즉, 글로벌 오브젝트에서 실행
    };
  1. get.call(this, 20)

    • 첫 번째 파라미터에 this 작성
  2. return param + this.value;

    • this가 글로벌 오브젝트를 참조하므로
    • (var value = 100)을 사용

call(()을 사용하지 않고

  1. return param + this.value;

    • get(20)으로 호출하면 this가 undefined를 참조하므로 에러 발생

Object 사용

var get = function(value){
  return this.base + this.rate + value;
};
var value = {base: 20, rate: 30};
var result = get.call(value, 50);
log(result);

// 650
  1. var result = get.call(value, 50);

    • call()의 첫 번째에 Object 작성
    • 50은 파라미터 값
  2. return this.base * this.rate + value;

    • this가 {base: 20, rate: 30}을 참조
    • 20 * 30 + 50
  3. this로 참조할 오브젝트를 변경할 수 있는 것이 call()의 특징


숫자 작성

function get(){
  return this.valueOf();
};
var result = get.call(123);
log(result);

// 123
  1. var result = get.call(123);

    • this가 오브젝트를 참조하므로
    • 숫자(123)를 작성하면 에러가 발생해야 하지만
  2. 값(123) 타입에 해당하는

    • Number 인스터스를 생성하고
    • 123을 프리미티브 값으로 설정
    • this가 Number 인스턴스를 참조

this 참조 변경

var book = {
  value: 123,
  point: {
    value: 456,
    get: function () {
      log(this.value);
    }
  }
};
book.point.get.call(book);
book.point.get.call(book.point);

// 123
// 456
  1. book.point.get.call(book);

    • book.point의 get() 호출
    • get()에서 this로 book 오브젝트 참조
    • this.value가 book.alue이므로 123 출력
  2. book.point.get.call(book.point);

    • book.point의 get() 호출
    • get()에서 this로 book.point 오브젝트 참조
    • this.value가 book.point.value이므로 456 출력

this와 apply()

  • getTotal.apply(this, [10, 20])
    • 함수 호출 방법은 call()과 같으며 파라미터가 배열인 것이 다름
    • [10, 20]을 파라미터 값으로 넘겨줌
  • 두 번째 파라미터 수가 유동적일 때 사용
    • call()은 파라미터 수가 고정일 때 사용

this와 arguments

var obj = {0: 10, 1: 20, 2: 30};
var data = [4, 5, 6];

function get(){
  for (k = 0; k < arguments.length; k++){
    log(arguments[k] + this[k]);
  };
};
get.apply(obj.data);

// 14
// 25
// 36
  1. get.apply(obj, data);

    • get() 함수에서 obj를 this로 참조
  2. 두 번째 파라미터 [4, 5, 6]을

    • arguments를 사용하여 계산
    • 파라미터 수가 유동적이므로 arguments가 편리
  3. get()으 함수 코드는 바뀌지 않으며

    • 넘겨 주는 파라미터 값과
    • this로 참조할 오브젝트만 변경하면 됨
  4. Array-like 형태


this와 콜백 함수

var obj = {value: 100};
var data = [5, 6, 7];

function callback(element, index, data){
  return element + this.value;
};
function get(data){
  return data.map(callback, obj);
};
var result = get(data);
log(result);

// [105, 106, 107]
  1. ES5의 map(), forEach()처럼

    • 콜백 함수가 있는 메소드는 두 번째 파라미터에 this로 참조할 오브젝트를 작성(option)
  2. function callback(element, index, data){
    return element + this.value;
    };

    • map()에서 호출하는 콜백 함수
  3. return data.map(callback, obj);

    • map()의 두 번째 파라미터에 obj를 작성
    • callback()에서 obj를 this로 참조
  4. map()의 코드는 바꾸지 않고

    • obj 값과 data 파라미터 값만 바꾸면 됨

this와 bind()

bind()

  • 두 번에 나누어 처리

    • function 오브젝트 생성
    • 생성항 function 오브젝트를 함수로 호출
  • 파라미터

    • 1번째 파라미터에 함수에서 this로 참조할 오브젝트
    • 2번째 파라미터에 호출된 함수의 파라미터 값
  • 생성한 function을 호출할 때에도 파라미터 작성 가능

    • 두 개의 파라미터를 병합하여 사용

function 오브젝트 생성, 호출

var book = {
  point: 123,
  get: function() {
    return this.point;
  }
};
var obj = book.get.bind(book);
log(typeof obj);
var result = obj();
log(result);

// function
// 123
  • var obj = book.get.bind(book);

    • book.get()을 호출하지 않고
    • function 오브젝트를 생성하여 반환
    • 생성한 function 오브젝트를 생성한 오브젝트의 [[TargetFunction]]에 설정
    • 처리를 나누어서 하므로 저장 필요
  • console.log(typeof obj);

    • obj의 타입은 function 오브젝트
  • bind()의 첫 번째 파라미터

    • get() 함수에서 this로 참조할 오브젝트 작성
    • get() 앞에 작성한 오브젝트를 this로 참조하지 않음
    • 작성하지 않으면 undefined 설정
    • 생성한 function 오브젝트의 [[BoundThis]]에 설정
  • var result = obj();

    • bind()로 생성한 function 오브젝트 호출
    • book.get() 함수가 호출됨
  • return this.point;

    • this가 [[BoundThis]]를 참조
    • 즉, book 오브젝트를 참조하므로 123 반환

파라미터 병합

var book = {
  get: function(){
    return Array.prototype.slice.call(arguments);
  }
};
var obj = book.get.bind(this, 10, 20);
var result = obj(30, 40);
log(result);

// [10, 20, 30, 40]
  • var obj = book.get.bind(this, 10, 20);

    • 두 번째, 세 번째 파라미터에 값을 작성했으며
    • book.get()의 파라미터 값으로 넘겨줌
    • function 오브젝트의 [[BoundArguments]]에 설정
  • get() 함수에 파라미터 이름을 작성하지 않고 arguments 사용

  • return Array.prototype.slice.call(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을 병합(첨부)하여 반환

bind() 활용, 이벤트 처리

var book = {
  myPoint: 100,
  setEvent: function(){
    var node = document.getElementById("point");
    node.onclick = this.show.bind(book, node);
  },
  show: function(node, event){
    log(node.textContent);
    log(this.myPoint);
  }
};
book.setEvent();

// 값 출력
// 100
  • 시나리오

    • "값 출력" 버튼을 클릭하면 값을 표시
  • HTML 형태:

	<script src="point.js" defer></script>
    <button id=point>값 출력</button>
  • 이벤트 처리의 어려움은
    • 이벤트를 설정할 때의 오브젝트를 핸들러에서 this로 참조할 수 없다는 것

➡️bind()로 해결할 수 있음

  • document.getElementById("point");

    • button#point로 엘리먼트 오브젝트 생성
  • node.onclick = this.show.bind(book, node);

    • show()는 onclick 이벤트의 핸들러
    • show()에서 this로 book 오브젝트를 참조하기 위해 바인드
    • show() 파라미터 값으로 node를 넘겨줌
  • show: function(node, event){

    • button#point를 클릭했을 때 호출됨
    • node: 이벤트를 설정한 엘리먼트
    • event: Event 오브젝트
  • console.log(this.myPoint);

    • bind() 첫 번째 파라미터에 book 오브젝트를 작성했으며
    • 이를 this로 참조하므로 123이 표시됨

0개의 댓글