Jun 개발노트

This is This

2021-11-07

Q. This에 대해서 설명해주세요.

  • 사전적 의미 : 이것, 어떠한것을 지칭하는 말
  • 자바스크립트에서의 의미: 호출한 실행환경(Execution Context)을 나타내는것
  • 멀티 쓰레드일 경우 (ex. 스칼라도 자바스크립트와 비슷하다)
    • callback을 호출 → 어떤 thread로 실행이 되는것인가? → 그건 실행환경에 따라 달라진다
    • 기본적으로 global(window)에서 호출된다.

1. 자바스크립트에서의 this

  • 해당 함수를 호출한 실행 컨텍스트(코드가 실행되는 곳)을 가리킨다. (런타임에 결정)

    const test = {
      prop: 42,
      func: function() {
        return this.prop;
      },
    };
    
    console.log(test.func());
    // expected output: 42
    
  • 단, new 키워드를 만나면, 해당 함수의 this는 생성자를 가르킨다.

    function Product(name, price) {
      this.name = name;
      this.price = price;
    }
    
    const cheese = new Product('feta', 5);
    
  • defaults : window (node환경: global)

  • strick-mode에서는 this === 'undefined'

2. this의 정확한 의미

  • 다른 언어(Java, Swift, 정적언어...?)

    • 생성되는 인스턴스를 가르킨다.
    //java
    public class Foo {
    		public String name;
        public String color;
            
        public Fruit(String name, String color) {
            this.name = name;
    				this.color = color;
        }
    }
    
    // swift
    class Bar {
      let row: Int, column: Int
    
      init(row: Int, column: Int) {
        self.row = row
        self.column = column
      }
    }
    
  • js

    • es6부터 Class 문법(사실은 함수...)을 지원하기 때문에, 위 언어와 비슷하게 동작한다.
    • babel을 활용하여, transpilering 해보면, 아래와 같이 this를 활용하여 호출하게 된다(링크)
    class Foo{
     constructor(name){
       this.name = name;
     }  
      
     foo(){
       console.log(this.name)
     }
    }
    
    // babel Compile
    // this
    var Foo = /*#__PURE__*/function () {
      function Foo(name) {
        _classCallCheck(this, Foo);
    
        this.name = name;
      }
    
      _createClass(Foo, [{
        key: "foo",
        value: function foo() {
          console.log(this.name);
        }
      }]);
    
      return Foo;
    }();
    

3. call, apply, bind

  • 정적바인딩 : bind

    • bind는 this가 지정된 함수를 리턴한다.

    • bind된 함수는 다시 bind 할 수 없다.

      const foo = {
        bar: 1,
        hello(){
          console.log(this.bar)
        }
      }
      // 전역변수
      bar  = 2;
      
      foo.hello()
      const a = foo.hello.bind(this)
      
      
  • 동적바인딩(default) : call, apply

    • call, apply는 this를 할당한 함수의 실행결과 를 리턴한다.

      // call
      function say(phrase) {
        alert(this.name + ': ' + phrase);
      }
      
      let user = { name: "John" };
      
      // this엔 user가 고정되고, "Hello"는 메서드의 첫 번째 인수가 됩니다.
      say.call( user, "Hello" ); // John: Hello
      
      // apply
      const numbers = [5, 6, 2, 3, 7];
      
      const max = Math.max.apply(null, numbers);
      
  • decorator 만들기

    • 함수의 역할은 그대로 두고, 기능을 더해준다 (데코레이터 패턴)

      function work(a, b) {
        console.log(a + b); 
      }
      
      function spy(func) {
        return function (...arg) {
          return func.apply(this, arg);
        };
      }
      
      work = spy(work);
      
      work(1, 2); // 3
      work(4, 5); // 9
      

4. 화살표 함수, 일반 함수의 차이

  • 일반 함수

    - this 호출한 컨텍스트
    - arguments 객체를 이용하여, 모든 인자를 받을 수 있음
    - new 키워드를 사용할 수 있음
    
  • 화살표 함수

    - this 렉시컬 컨텍스트 (선언될때, 이미 this가 할당)
    - arguments 객체가 없음..
    - new 키워드를 사용하여 호출 할 수 없음
    

5. event handler의 this

// html
<button id="foo">FOO</button>

<button>
	<span id="bar">BAR</span>
</button>

$foo.addEventListener('click', function () {
  console.log('function this', this)   // <button id="foo">FOO</button>
})

$foo.addEventListener('click', () => {
  console.log('arrow function this', this) // window
})

$bar.addEventListener('click', function () {
  console.log('function this', this) // <span id="bar">BAR</span>
})