Skip to content

Instantly share code, notes, and snippets.

@snaag
Created May 13, 2020 09:46
Show Gist options
  • Save snaag/990aa6a6d3d9461ff2da16dbf4b07c3d to your computer and use it in GitHub Desktop.
Save snaag/990aa6a6d3d9461ff2da16dbf4b07c3d to your computer and use it in GitHub Desktop.

들어가며

생성자와 this 에 대해서 알아보았다.

개인적으로 생성자 함수라는 말 보다는 함수의 생성자가 맞다고 생각하지만, 생성자라고 작성하면 읽는데 헷갈리는 부분이 있을 것 같아 이해를 위해 생성자 함수라고 적었다.

  • 인사이드 자바스크립트 Ch.4.4를 참고하였다.

생성자와 this

예를 들어 이런 코드가 있다고 해보자.

function foo() {
  this.name = 'foo';
  // ...
}

var bar = new foo();

barfoo 에게 접근할 수 있다.

이것이 가능한 이유는 bar 가 생성될 때 foo()constructor 로 하여금, bar.__proto__foo()의 prototype 객체를 가리키게끔 했기 때문이다.

그리고 이 때 새롭게 생성된 new objectthisbar 에 바인딩이 된다. 그리고 이러한 바인딩을 new 바인딩 이라고 한다. (여기에 추가적인 설명이 있다)

그런데 만약 new 를 사용하지 않고 객체를 만들면 어떻게 될까?

생성자 함수를 new를 붙이지 않고 호출할 경우

그냥 함수를 실행한 결과와 같다.

function Person(name) {
  this.name = name;
}

var qux = Person('qux');

console.log(qux); // undefined
console.log(window.name); // qux

즉 새로 만든 객체에 올바르게 값이 들어가지 않는다. 이런 불상사를 막기 위해 대부분의 라이브러리는 내부적으로 아래와 같은 처리를 해준다고 한다.

new 를 붙이지 않아도 안전한 함수 만들기

function PersonSafe(name) {
  if (!(new.target))
    return new PersonSafe(name);
  
  this.name = name;
}

var quxSafe = PersonSafe('qux');
console.log(quxSafe); // 결과는 아래에 있다
PersonSafe {name: "qux"}
  name: "qux"
  __proto__: Object

PersonSafe 안에서 new 의 여부를 체크한 뒤에, 없다면 new 키워드로 재귀적으로 함수를 호출 한다.

그리고 !(new.target) 부분이 책에서는 !(this instanceof arguments.callee) 라고 되어있는데, StackOverflow에서 !(new.target) 가 맞는 표현이라고 하더라. 채택된 답변의 하단에 해당 내용이 있다.

(저 게시물은 내가 올린 질문이었는데 질문 올릴 당시에는 계속 고민하다가 올린건데, 댓글을 보고 바로 이해했다. 내 질문이 바보같았다는것을 ㅎㅎ;;)

생성자 함수가 아무것도 return하지 않을 경우

일반적인 함수의 return

일반적인 함수는 return 값이 명시되어있지 않으면 undefined 를 반환한다.

function printMe(name) {
  console.log(name);
}

printMe("snaag"); // snaag
									// undefined

그렇다면 생성자 함수는 return 값이 있을 때와 없을 때가 어떻게 다를까?

생성자 함수의 return

따로 return 을 해주지 않았을 경우, this 로 바인딩 된 새로운 객체를 반환한다. (일반적인 반환을 한다)

function Person(name, age, gender) {
  this.name = name;
  this.age = age;
  this.gender = gender;
}

var qux = new Person('qux', 20, 'man');
console.log(qux.name);	 // qux
console.log(qux.age);		 // 20
console.log(qux.gender); // man

return 을 명시해 준 경우, 해당 객체를 return 한다.

function Person(name, age, gender) {
  this.age = age;
  
  return {name, gender};
}

var qux = new Person('qux', 20, 'man');
console.log(qux); // {name: "qux", gender: "man"}
console.log(age); // ReferenceError: age is not defined

만약 keyvalue 를 아예 다르게 바꿔도, 결과는 동일하다

function Person(name, age, gender) {
  return {'hehe':name, 'hehehe':'hehe'};
}

var qux = new Person('qux', 20, 'man');
console.log(qux); // {hehe: "qux", hehehe: "hehe"}

그러나 함수가 return 하는 값이 객체가 아니라 Boolean, Number, String 의 경우에는 이러한 반환 값을 무시하고 this 로 바인딩 된 객체가 반환된다.

정리

new 키워드 없이 생성자 함수를 호출할 경우에는, 함수의 코드가 그냥 실행만 된다. 따라서 이러한 것을 막기 위해 new.target 속성으로 재귀적으로 함수를 만들 수 있다.

생성자 함수가 아무것도 return 하지 않을 때에는 this 로 바인딩 된 새로운 객체를 반환한다. 객체를 return 할 경우에는 해당 객체가 반환되지만, 만약 Boolean, Number, String 의 경우에는 이러한 반환 값을 무시하고 this 로 바인딩 된 객체가 반환된다.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment