TIL19. 자바스크립트의 This

imloopy·2022년 4월 9일
0

Today I Learned

목록 보기
19/56

Today I Learned

오늘은 자바스크립트의 this 에 대하여 정리하기로 했다. 어? 분명히 정리했던 것 같은데 왜 또 정리하지? -> 오늘 면접스터디를 했는데 이 파트에 대하여 정리하기로 했기 때문이다. 그래서 저번보다는 조금 더 자세히 적어보려고 한다.

this

함수를 호출 시, 우리가 직접 전달하는 arguments들 외에도 암묵적으로 this를 전달하게 된다. 아마 일반적인 다른 언어에서는 this(self)는 인스턴스 자신을 가리키는 참조 변수일 것이다. 그러나 자바스크립트에서 this는 다른 언어와는 달리 호출 주체가 누구인지, 함수의 호출 방식에 따라 달라진다.

this의 호출 방식

1. 일반적인 함수에서 호출

함수를 호출하는 방법은 총 4가지가 있으며, 이 호출방식에 따라 this값은 달라진다.
1. 일반적인 함수 키워드 function으로 this 호출
2. 생성자 함수로서 호출
3. 메소드 호출
4. call/apply/bind함수로 호출

1. 일반적인 함수로 호출

일반적인 함수에서 this 호출 시, 기본적으로 전역 객체를 가리킨다.

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

2. 생성자 함수로서 호출

자바스크립트는 생성자 함수가 따로 있는게 아니고, 그냥 new 키워드를 붙여서 함수를 호출한다면, 그 함수는 생성자 함수가된다. new 키워드를 통해 함수를 호출할 경우, this는, 호출한 인스턴스를 가리킨다.

function Person(name) {
  this.name = name;
  console.log(this);
  this.greet = () => console.log(`hello, ${this.name}!`);
}
const peter = new Person('peter'); // this는 instance를 가리킴
peter.greet(); // hello, peter!

3. 메소드로 호출

객체 리터럴 내부에서 함수를 호출한다면, this는 객체를 가리킨다.

function foo() {
  console.log(this);
}

foo(); // window

const bar = { foo: foo };
bar.foo(); // bar

4. call/apply/bind 호출

call/apply/bindthis를 명시적으로 바인딩할 수 있다.

var value = 1;

var obj = {
  value: 100,
  foo: function() {
    console.log("foo's this: ",  this);  // obj
    console.log("foo's this.value: ",  this.value); // 100
    function bar(a, b) {
      console.log("bar's this: ",  this); // obj
      console.log("bar's this.value: ", this.value); // 100
      console.log("bar's arguments: ", arguments);
    }
    bar(); // window
    // 바인딩 함수로 바인딩할 경우, 인스턴스 또는 객체의 this를 따르게 할 수 있다.
    bar.apply(obj, [1, 2]);
    bar.call(obj, 1, 2);
    bar.bind(obj)(1, 2);
  }
};

obj.foo();

2.Arrow function에서 this 호출

Arrow Function은 일반적인 함수보다 좀 더 간결하게 사용할 수 있는 표현식이다. arrow function과 일반 함수와의 가장 큰 차이점은 this이다. arrow function은 this를 바인딩하지 않는다. 그렇기 때문에 무조건 상위 스코프의 this를 따른다. 또한, call/apply/bind 함수로 this 바인딩 역시 불가능하다.

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  // (A)
  return arr.map(function (x) {
    return this.prefix + ' ' + x; // (B)
  });
};

var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

B의 this는 전역 객체 window를 가리킨다. 기본적으로 일반 함수의 this는 전역 객체를 가리키기 때문이다. (메소드로 호출된 첫번째 함수의 this만 인스턴스를 가리킨다.)
따라서 내가 의도한 로직을 실행하기 위해서는 call/apply/bindthis를 바인딩하여야 한다.

Prefixer.prototype.prefixArray = function (arr) {
  // (A)
  return arr.map(function (x) {
    return this.prefix + ' ' + x; // (B)
  }.bind(this)); // 이런식으로
};

하지만 ES6에서 새롭게 추가된 화살표 함수는, 무조건 상위 스코프의 this를 따라가므로 바인딩할 필요가 없다.

// arrow function
Prefixer.prototype.prefixArray = function (arr) {
  return arr.map((x) => this.prefix + ' ' + x); // 이런식으로
};

3.use strict에서 this

ES5에서 새롭게 추가된 엄격모드는, 느슨한 체킹을 했던 자바스크립트에 엄격한 타입 체킹과, 조용이 무시되던 에러들을 반환하는 모드이다. this를 명시하지 않았다면, 전역 객체가 아닌 undefined를 반환한다.

function f() {
  return this;
}
console.log(f()); // undefined
console.log(f().call(2)); // 2
console.log(f().apply(null)); // null
console.log(f().bind('string'); // string

출처

모던 자바스크립트 Deep Dive
strict mode - MDN

0개의 댓글