Today
-
Yesterday
-
Total
-
  • [JavaScript] 자바스크립트 this의 모든 것
    Web/JavaScript 2021. 5. 15. 21:12

    this란 무엇인가?

     C++, JAVA 등 다양한 프로그래밍 언어에서도 this가 존재하는데, 여기서 this는 객체 자신을 나타내는 포인터, 레퍼런스다.
    하지만 자바스크립트에서 this는 함수의 호출 맥락(Context)를 의미한다. 즉 함수를 어떻게 호출하냐에 따라 this가 가리키는 대상이 달라질 수 있다는 것이다. 함수와 객체의 관계가 느슨한 자바스크립트에서 this는 이 둘을 연결 시켜주는 역할을 한다.

    console.log(this); // window
    
    function func1() {
    	console.log(this);
    }
    
    func1(); // window

    우선 브라우저의 개발자 도구에서 this를 출력 해보면 전역 객체인 window 객체를 출력한다. (node.js에서는 this를 출력하면 빈 객체 { } 가 나온다) 뿐만 아니라 func라는 함수 안에서 this를 출력 해보아도 똑같이 window 객체를 출력한다.

    더보기

    strict 모드에서는 this에 디폴트 바인딩이 없기 때문에 undefined를 출력한다.

    "use strict";
     
    function myFunction() {
      return this;
    }
    console.log(myFunction()); //undefined
    

    메소드에서 this

    const obj = {
      func2: function () {
      	console.log(this); // obj 객체를 출력
      }
    }
    
    obj.func2();

    위의 코드를 보면 obj라는 객체의 메소드 func2에서의 this는 func2가 소속 되어있는 객체 obj를 가리키는 것을 알 수 있다. 사실 처음 설명한 코드와 같은 원리인데, 처음 설명한 func1는 window라는 객체의 메소드 window.func1()라고도 볼 수 있기 때문에 func1 안의 this는 window를 가리켰던 것이다.

    생성자에서 this

    생성자 안에서 this는 그 생성자가 만든 객체를 나타낸다.

    function func () {
      console.log(this);
    }
    
    func(); // window
    
    const A = new func(); // func { }

    다양한 형식의 메소드와 this를 출력해 보았다.

    var obj = {
    	func: function() {
        	return this;
        },
        func2: function() {
        	var obj2 = {
            	func: function() {
                	return this;
                }
            }
            return obj2.func();
        },
        func3: function() {
          function func4() {
            return this;
          }
          return func4;
        },
        func5: () => {
          return this;
        }
    }
    
    function func6() {
      return this;
    }
    
    console.log(obj.func()); // obj
    console.log(obj.func2()); // obj2
    console.log(obj.func3()); // func4
    console.log(obj.func5()); // { }
    console.log(func6); // func6
    console.log(new func6()); // func5 {}

    때문에 만약 함수를 생성자를 사용하지 않고 호출을 한다면 해당 함수에서 this 는 전역 객체인 window를 가리키므로 원치않는 데이터 변경이 되지 않도록 주의해야한다.

    var data = 'important';
    
    function func(value) {
      this.data = name;
    }
    
    var tmp = func('Hello');
     
    console.log(window.data); // Hello
    

    이벤트 핸들러 안의 this

    이벤트 핸들러에서 this는 이벤트를 받는 HTML 요소를 가리킨다.

    const btn = document.querySelector('#btn');
    
    btn.addEventListener('click', function () {
      console.log(this); //#btn
    });

    함수 바인딩 (apply, call, bind)

    일반적으로 객체와 메소드는 Master-Slave 관계를 가지고 있다.
    하지만 함수의 메소드인 bind, apply, call를 사용한다면 Master인 객체를 (this의 값을) 제어 할 수 있다.
    그렇다면 이 세가지 메소드는 어떤 차이가 있는지 알아보자.

    1. apply

    함수의 메소드인 apply를 이용하면 해당 함수에서 사용되는 this가 어떤 객체를 나타 낼 것인지 직접 설정한다.

    var o = {};
    var p = {};
    
    function func(){
      console.log(this);
    }
    
    func(); // window
    func.apply(o); // o { }
    func.apply(p); // p { }
    func(); // window

    apply를 사용하더라도 실제 func가 속한 객체를 바꾼 것이 아니기 때문에 마지막에 다시 호출한 func()에서는 다시 window 객체를 가리킨다.

    2. call

    apply와 call 두 메소드는 거의 흡사하다. 둘의 유일한 차이점은, 바인딩 할 함수에 인자가 있을 때, 파라미터로 배열을 넣냐, 여러개의 파라미터를 값으로 넣냐다. apply는 배열을 인자로 받고, call은 다수의 파라미터를 인자로 받는다. 아래의 예시를 보자.

    window.num = 0;
    
    function sum(num1, num2){
      return console.log(this.num + num1 + num2);
    }
    
    const obj = { num : 100 }
    
    sum(1, 2); // 3
    sum.call(obj, 1, 2); // 103
    sum.apply(obj, [1, 2]); // 103

    예시를 보면 call이나 apply나 인자의 형태만 다를 뿐 바인딩 된 객체나 전달 된 인자들은 모두 같다는 것을 알 수 있다.

    3. bind

    bind는 새롭게 바인딩 한 함수를 만든다. 여기서 주의 할 점은 bind()는 call(), apply()와 같이 함수가 가리키고 있는 this를 바꾸지만 호출되지는 않는다.

    window.num = 0;
    
    function sum(num1, num2){
      return console.log(this.num + num1 + num2);
    }
    
    const obj = { num : 100 }
    
    const sum2 = sum.bind(obj); // 함수가 호출되지 않기 때문에 출력 없음
    sum(1, 2); // 출력: 3
    sum2(1, 2); // 출력: 103

    댓글