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 오브젝트에 설정된다.
  • 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 오브젝트 반환
    • 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을 출력
  • 정리 예제 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
  • 정리 예제 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()을 호출한다.
  • 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이다.
          • 에러가 발생한다.
    • 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()의 특징
    • 숫자 작성
      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 인스턴스를 참조합니다.
    • 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 출력
  • 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 형태
    • call 함수와 apply 함수를 사용하는 이유는 참조할 객체와 데이터가 변경되더라도 재사용 가능하도록 설계 및 구현하기 위해서이다.
  • 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 파라미터 값만 바꾸면 된다.
  • 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 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을 병합(첨부)하여 반환
    • 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. 인프런 강좌_자바스크립트 중고급: 근본 핵심 이해