this

BenKim·2020년 6월 10일
0

자바스크립트의 함수는 호출될 때 매개변수로 전달되는 인자값 이외에 arguments객체와 this를 암묵적으로 전달받는다.
자바스크립트의 this는 함수 호출 방식에 따라 this에 바인딩할 어떤 객체가 동적으로 결정된다.
함수의 호출방법은 4가지정도된다.

this바인딩의 우선순위
1. new로 함수를 호출했다면 실행결과 반환되는 값이 this다
2. call, apply, bind로 함수를 호출한경우의 this
3. 객체의 메소드로서의 함수. 객체가 this
4. 이외의경우는 전역객체가 this다.

1. var obj = new hello(); // this === obj
2. var obj = {}
    hello.call(obj) // this === obj
    hello.apply(obj) // this === obj
    hello.bind(obj)() // this === obj
3. obj.hello(); // this === obj

  1. 함수호출
    전역객체는 모든 객체의 유일한 최상위 객체를 의미하여 일반적으로 브라우져에서는 window, 노드js에서는 global 객체를 의미한다.
foo();
this === window // true

글로벌 영역에 선언한 함수는 전역객체의 프로퍼티로 접근할 수 있는 전역변수의 메소드이다.

function foo() {
  console.log('invoked');
}
window.foo();

이때 전역함수는 물론 내부함수까지 this는 외부함수가 아닌 전역객체에 바인딩된다.
메소드의 내부함수일 경우에도 this는 전역객체에 바인딩된다.

var obj ={
  foo : function(){
    console.log(this); //obj
    function bar() {
      console.log(this) //window
    }
    bar()
  }
};

콜백함수의 경우에도 this는 전역객체에 바인딩된다.

function() {
  setTimeout(funciton() [
    console.log(this) //window
    }, 100);

내부함수는 일반함수, 메소드, 콜백함수 어디에서 선언되었든 관계없이 this는 전역객체를 바인딩한다.
내부함수의 this가 전역객체를 참조하는것을 명시적으로 막는 방법으로 apply, call, bind가 있다.

function bar(a,b){
  console.log(this) //obj
}
bar.apply(obj,[1,2]);
bar.call(obj, 1,2);
bar.bind(obj)(1,2);
  1. 메소드 호출
    함수가 객체의 프로퍼티 값이면 메소드로서 호출된다.
    이때 메소드 내부의 this는 상위 객체에 바인딩된다.
var obj1 = {
  name: 'Lee',
  sayName: function() {
    console.log(this.name);
  }
}

var obj2 = {
  name: 'Kim'
}

obj2.sayName = obj1.sayName;

obj1.sayName(); // Lee
obj2.sayName(); // Kim
  1. 생성자 함수 호출
    자바스크립트에서는 기존함수에 new 연산자를 붙여서 호출하면 해당함수는 생성자 함수로 동작한다.
// 생성자 함수
function Person(name) {
  this.name = name;
}

var me = new Person('Lee');
console.log(me); // Person {name: "Lee"}

새로 생성된 객체에서의 this는 생성된 자신을 가리키기때문에 this를 통해 생성한 프로퍼티와 메서드는 새로 생성된 객체에 추가된다.

  1. apply/ call/ bind 호출
    call()메소드는 주어진 this값 및 각각 전달된 인자와 함께 함수를 호출한다.
    call은 인자목록을, apply는 인수배열하나를 받는다.
    bind는 this를 명시하는점에서는 같지만 함수를 실행시키지 않는다는 차이점이 있다.
function.apply(this바인딩할 객체, [함수에 전달한 args배열]);
function.call(this바인딩할 객체, 1, 2, 3);

생성자 함수에서의 사용예시

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  // Product실행결과(name,price포함) 를 가져오지만 this는 Food생성자.
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"

생성자로 쓰이는 함수에는 화살표함수를 사용할 수 없다. (이름이 없고 this를 바인딩하지 않기때문)

setTimeout 에서 bind의 사용

function hello() {
  console.log(this.name);
}

var obj = {
  name: 'chris',
  hello: hello
};

setTimeout(obj.hello, 1000); // 1초 후에 hello 함수가 동작하면 this는?

name = 'global context!';

setTimeout()함수에 콜백함수로 obj.hello를 넘겨줬다. setTimeout측에서는 obj객체와는 전혀 상관없이 obj.hello가 가리키는 hollo()함수만 알고있다. 1초후에 실행하는 코드는 hello()함수를 기본 바인딩해서 실행하는것과 동일하다.

그래서 '난 이객체를 컨택스트로 바인딩할거야'라고 코드에 명시적으로 표시하는 방법이있다. 같은코드인데 setTimeout에서 실행컨텍스트가 뭔지 표시해줬다.

function hello() {
  console.log(this.name);
}

var obj = {
  name: 'chris',
};

name = 'global context!';
hello.call(obj); // "chris"
profile
연습과 자신감

0개의 댓글