User 함수
와 같은 생성자를 만들 때, 호출자는 반듣시 new
연산자를 통해 호출해야 한다.
function User(name, age){
this.name = name
this.age = age
}
new 키워드
를 깜빡했다면 어떻게 될까?var u = User("이순신",45);
u; // undefined
this.name ;// 이순신
this.age ;// 45
함수의 수신자 객체는 전역 객체
가 되버린다. 함수가 undefined를 반환할 뿐만 아니라 전역변수에 name과 age가 이미 존재한다면 수정하게 된다.
function User(name, age){
"use strict"
this.name = name
this.age = age
}
var u = User("이순신",45); //오류 : this가 정의되지 않음
“use strict” 를 사용하면 잘못된 호출로 인한 오류가 발생한다. 이처럼 스트릭트 모드를 사용하면 호출자는 버그를 빨리 발견하고 고칠 수 있다.
function User(name, age){
if(!this instanceof User){
return new User(name,age)
}
this.name = name
this.age = age
}
new 연산자
없이 생성자 함수를 실행한다면 this
는 전역객체
가 되기 때문에 User의 인스턴스
가 아니게 된다. 그점을 이용하여 다음과 같은 코드를 작성하면 new 키워드
없이 생성자를 사용할 수 있다.
var x = User("이순신", 45);
var y = new User("강감찬", 42);
x instanceof User //true
y instanceof User //true
이 패턴의 단점은 추가적인 함수 호출이 필요하기 때문에 약간의 비용이 더 든다는 점이다.
function User(name, age){
var self=. this instanceof User ? this : Object.create(User.prototype);
self.name = name;
self.age = age;
return self;
}
Object.create를 사용하여 prototype을 직접 지정한 객체를 사용하여 반환하였다.
if(typeof Object.create === 'undefined'){
Object.create = function(prototype){
function C(){}
c.prototype = ptototype;
return new C();
}
실제 Object.create() 함수는 가변인자를 사용하지만 여기서는 prototype만 설정할 수 있게 해두었다.
생성자 함수 내에서 명시적으로 return
을 실행할 경우 new표현식의 결과
를 오버라이딩
하도록 허용하기 때문이다. 이게 무슨말인지 코드로 살펴보자
function Person(name){
this.name = name;
return 42;
}
var person = new Person('Alice');
console.log(person) // Person{name:'Alice'}
return 으로 42를 반환하고 있지만 호출 결과는 여전히 Person의 인스턴스
가 된다. 42는 무시되고 생성자 함수가 정의한대로 this에 바인딩 된 객체
가 새성된다.
function Person(name) {
this.name = name;
return { age: 30 }; // 생성자 함수 내에서 객체를 반환
}
var person = new Person('Alice');
console.log(person); // { age: 30 }
이 경우에는 return으로 반환한 { age: 30 }
이 반환된다. 리턴값으로 객체를 반환
하기 때문이다. 이러한 동작을 오버라이딩
이라고 한다.
생성자 함수는 new를 통해 호출되어야함을 문서화 하면 또한 오류를 방지할 수 있다.
new
로 다시 호출하거나 Object.create
를 사용해서 생성자가 호출자의 문법에 관계없이 동작할 수 있게 하자new
로 호출되기를 기대한다면, 이에 대해 명백하게 문서화 하자