객체 리러털 {...}을 사용하면 객체를 쉽게 만들 수 있다. 그런데 개발을 하다 보면 유사한 객체를 여러 개 만들어야 할 때가 생기곤 합니다. 복수의 사용자, 메뉴 내 다양한 아이템을 객체로 표현하려고 하는 경우가 그렇죠
new 연산자와 생성자 함수를 사용하면 유사한 객체 여러 개를 쉽게 만들 수 있다.
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("보라");
console.log(user.name); // 보라
console.log(user.isAdmin); // false
new User(...)를 써서 함수를 실행하면 아래와 같은 알고리즘이 동적
- 빈 객체를 만들어 this에 할당
- 함수 본문을 실행 this에 새로운 프로퍼티를 추가해 this를 수정
- this를 반환
예시를 이용해 new User가 실행되면 무슨 일이 일어나는지 살펴 보도록 하겠음.
function User(name) {
// this = {}; (빈 객체가 암시적으로 만들어짐)
// 새로운 프로퍼티를 this에 추가함
this.name = name;
this.isAdmin = false;
// return this; (this가 암시적으로 반환됨)
}
이제 let user = new User("보라")는 아래 코드를 입력한 것과 동일하게 동작합니다.
let user = {
name: "보라",
isAdmin: false
};
new User("보라") 이외에도 new User("호진"), new User("지민") 등을 이용하면 손쉽게 사용자 객체를 만들 수 있다. 객체 리터럴 문법으로 일일이 객체를 만드는 방법과 훨씬 간단하고 읽기 쉽게 객체를 만들 수 있다.
생성자의 의의는 바로 여기에 있습니다. 재사용할 수 있는 객체 생성 코드를 구현
잠깐! 모든 함수는 생성자 함수가 될 수 있다는 점을 잊지 마시기 바랍니다. new를 붙여 실행한다면 어떤 함수라도 위에 언급된 알고리즘이 실행. 이름의 '첫 글자가 대문자'인 함수는 new를 붙여 실행해야 한다는 점도 잊지 마세요. 공동의 약속
new fucntion(){...}
재사용할 필요가 없는 복잡한 객체를 만들어야 한다고 해봅시다. 많은 양의 코드가 필요 이럴땐 아래와 같이 코드를 익명 생성자 함수로 감싸주는 방식을 사용
let user = new function(){
this.name = "John"
this.isAdmin = false;
//사용자 객체를 만들기 위한 여러 코드.
// 지역 변수, 복잡한 로직, 구문 등의
// 다양한 코드가 여기에 들어갑니다.
}
위 생성자 함수는 익명 함수이기 때문에 어디에도 저장되지 않습니다. 처음 만들 때부터 단 한 번만 호출할 목적으로 만들었기 때문에 재사용이 불가능합니다. 이렇게 익명 생성자 함수를 이용하면 재사용은 막으면서 코드를 캡슐화 할 수 있습니다.
심화 학습
new.target 프로퍼티를 사용하면 함수가 new와 함께 호출되었는지 아닌지를 알 수 있다.
일반적인 방법으로 함수를 호출했다면 new.target은 undefiend를 반환 반면 new와 함께 호출한 경우엔 new.target은 함수 자체를 반환
function User() {
console.log(new.target);
}
// 'new' 없이 호출함
User(); // undefined
// 'new'를 붙여 호출함
new User(); // function User { ... }
function User(name) {
if (!new.target) { // new 없이 호출해도
return new User(name); // new를 붙여줍니다.
}
this.name = name;
}
let bora = User("보라"); // 'new User'를 쓴 것처럼 바꿔줍니다.
console.log(bora.name); // 보라
라이브러리를 분석하다 보면 위와 같은 방식이 쓰인 걸 발견할 때가 있을 겁니다. 이런 방식을 사용하면 new와 붙여 함수를 호출하든 아니든 코드가 동일하게 동작하기 때문에, 좀 더 유연하게 코드를 작성
그런데 이 방법을 믿고 객체를 만드는 경우에도 new를 생략하면 코드가 정확히 무슨 일을 하는지 알기 어렵다. new가 붙어있으면 새로운 객체를 만든다는 걸 누구나 알 수 있기 때문에 new를 생략해서 객체를 만드는것은 정말 필요한 경우에만 사용하시고 남발하지 않아야 한다.
그런데 만약 return 문이 있다면 어떤 일이 벌어질까요? 아래와 같은 간단한 규칙이 적용
객체를 return한다면 this 대신 객체가 반환
원시형을 retrun한다면 retrun문이 무시됩니다.
return 뒤에 객체가 오면 생성자 함수는 해당 객체를 반환해주고, 이 외의 경우는 this가 반환
function BigUser() {
this.name = "원숭이";
return { name: "고릴라" }; // <-- this가 아닌 새로운 객체를 반환함
}
console.log( new BigUser().name ); // 고릴라
function SmallUser(){
this.name ="원숭이";
return ; // <--this 반환
}
console.log(new SmallUser().name); //원숭이
let user = new User; // <-- 괄호가 없음
// 아래 코드는 위 코드와 똑같이 동작합니다.
let user = new User();
function User(name) {
this.name = name;
this.sayHi = function() {
alert( "제 이름은 " + this.name + "입니다." );
};
}
let bora = new User("이보라");
bora.sayHi(); // 제 이름은 이보라입니다.
/*
bora = {
name: "이보라",
sayHi: function() { ... }
}
*/
위 내용은 javascript.info 사이트에서 공부한 내용 정리
자세한 내용은 아래 링크를 참고하세요
https://ko.javascript.info/constructor-new