[바닐라코딩 프렙] This 예제 모음

Suh, Hyunwook·2021년 8월 15일
0
post-thumbnail

Javascript의 This에 대한 설명을 읽으면 설명의 예제로는 이해하기가 난해하지는 않으나, 실제 코드로 마주할 경우에는 복잡한 코드 속의 This는 꽤나 헷갈리는 부분이 있다. 따라서, 아래 예제를 정리해보고자 한다.

출처는 Dmitri pavlutin, Annie Riao,
Sagiv ben giat
님의 블로그 및 Lydia Hallie님의 github에 등록된 문제들을 다뤄볼 예정이다. 양질의 문제를 수록해주신 분들 및 양질의 문제를 공유해주신 프렙 수강생 여러분들께 감사합니다 !

먼저, This는 함수가 실행되는 순간에 결정된다는 부분을 상기할 필요가 있다. 이 때문에, This값을 판별하기 위해서는 함수의 실행문을 분석해야한다.

1. Regular Function Call
2. Dot Notation 또는 대괄호 호출
3. Call, Apply, Bind
4. "new" Keyword (생성자)

함수가 실행될 수 있는 방식으로는 위 4가지 경우가 있다. 이러한 실행방식을 바탕으로 아래 예제를 분석해보도록 하겠다.

Q1. 아래 코드에서 출력되는 값은 무엇인가?

function Pet(name) {
  this.name = name;
  this.getName = () => this.name;
}
const cat = new Pet('Fluffy');
console.log(cat.getName()); // What is logged?

해설: new Pet('Fluffy') 생성자(constructor)로서 함수가 호출될 경우, this의 값은 cat이 된다. 이에 따라, this.nameFluffy가 된다. this.getName = () => this.name은 화살표 함수로서 this를 별도로 바인딩할 필요없이, 외부 스코프의 this를 참조하므로, 역시 cat이 된다. 즉, cat.getName()Fluffy가 된다.

Q2. 아래 코드에서 출력되는 값은 무엇인가?

const object = {
  message: 'Hello, World!',
  logMessage() {
    console.log(this.message); // What is logged?
  }
};
setTimeout(object.logMessage, 1000);

해설: object.logMessage()로 실행하였을 경우에는 dot notation 방식이기 때문에, this에 object가 바인딩되어, Hello, World를 출력하지만, setTimeout가 실행될 경우 task queue에 logMessage()가 담기게 되고, 일반함수로 실행되기 때문에 this에는 전역객체가 바인딩된다. 전역에 message 프로퍼티가 없으므로 undefined가 출력된다.

Q3. 아래 코드를 완성하여 "Hello, World"를 출력하시오.

const obj = {
  message: 'Hello, World!'
};
function logMessage() {
  console.log(this.message); // "Hello, World!"
}
// Write your code here..

해설: call,apply,bind를 사용하면 다음과 같다. 우선 callapply의 경우 this를 바인딩 후 즉시 실행하는 함수이므로 다음과 같이 사용할 수 있다.
logMessage.call(obj),logMessage.apply(obj)
bind의 경우, this를 바인딩 후 새로운 함수를 반환하며, 실행하지는 않는 메서드이다. 또한 반환된 이 함수를 실행해야 원본함수가 실행된다.

const boundLogMessage = logMessage.bind(obj)
boundLogMessage();

Q4. 아래 코드에서 출력되는 값은 무엇인가?

const object = {
  who: 'World',
  greet() {
    return `Hello, ${this.who}!`;
  },
  farewell: () => {
    return `Goodbye, ${this.who}!`;
  }
};
console.log(object.greet());    // What is logged?
console.log(object.farewell()); // What is logged?

해설: "Hello, world!", "Goodbye, undefined"가 출력된다. 첫번째 greet()함수의 경우, dot notation으로 출력이 되어, this 값에 object가 바인딩되었지만, farewell의 경우, 화살표 함수이며, this를 별도로 바인딩해주지 않는 이상, 실행되면 외부 스코프인 전역의 this를 참조하게 되어, undefined를 return한다.

Q5. 아래 코드에서 출력되는 값은 무엇인가?

var length = 4;
function callback() {
  console.log(this.length); // What is logged?
}
const object = {
  length: 5,
  method(callback) {
    callback();
  }
};
object.method(callback, 1, 2);

해설: this값은 함수가 실행될 때 결정되므로, 함수의 실행문부터 역추적하면 된다. this.lengthcallback 함수 안에 있으며, callback 함수는 method함수에서 일반함수로 실행이 되었으므로, this는 전역객체가 바인딩되어, 4를 출력하게 된다.

Q6. 아래 코드에서 출력되는 값은 무엇인가?

var length = 4;
function callback() {
  console.log(this.length); // What is logged?
}
const object = {
  length: 5,
  method() {
    arguments[0]();
  }
};
object.method(callback, 1, 2);

해설: 답은 3이다. callback()object.method(callback, 1, 2)가 실행될 때 전달받은 method() 안의 arguments, 즉 유사배열객체 안의 프로퍼티인 callback을 대괄호방식으로 실행한 것이므로, this에는 arguments가 바인딩된다.

{
  0: callback,
  1: 1,
  2: 2,
  length: 3
}

Q7. 아래 코드에서 출력되는 값은 무엇인가?

var status = "Happy";
setTimeout(function foo() {
  const status = "Satisfied";
  const data = {
    status: "Gloomy",
    getStatus() {
      return this.status;
    }
  };
  console.log(data.getStatus());
  console.log(data.getStatus.call(this));
}, 0);

해설: data.getStatus()의 경우, "Gloomy", data.getStatus.call(this)의 값은 "Happy"가 출력된다. This의 값은 호출할 때 결정이 된다. data.getStatus()의 경우, SetTimeout이 실행된 후 foo()함수 내부에서 data의 메소드로 출력하는 경우로서, getStatus() Scope에서는 this가 data가 되므로, "Gloomy"가 출력된다. data.getStatus.call(this)의 경우, setTimeout과 같은 함수에서는 This에 전역이 바인딩(strict 모드에서는 undefined)되며, 따라서 "Happy"가 출력된다.

0개의 댓글