생성자 함수에 의한 객체 생성
Object 생성자 함수
새로운 객체를 생성할 때 사용된다
빈 객체 생성
var obj = new Object();
객체 리터럴과 유사한 형태로 객체 생성
var obj = new Object({ name: 'John', age: 25 });
다른 객체를 복사하여 새로운 객체생성
var oldObj = { name: 'John', age: 25 };
var newObj = new Object(oldObj);
⇒객체 리터럴을 사용하여 객체를 생성하는 것이 더 간편하고 직관적
생성자함수
자바스크립트에서 객체를 생성하기 위해 사용되는 함수 생성자 함수는 일반 함수와 동일한 방식으로 정의되지만, 객체를 생성할 때 new 연산자를 사용하여 호출
- 새로운 빈 객체를 생성
- 이 빈 객체의 프로토타입을 생성자 함수의 프로토타입 객체로 설정
- 생성자 함수 내부의 this를 빈 객체로 설정
- 생성자 함수 내부의 코드를 실행하여 이 빈 객체에 프로퍼티와 메소드를 추가
- 빈 객체를 반환
function Person(name, age) {
this.name = name;
this.age = age;
}
var john = new Person('John', 25);
객체 리터럴에 의한 객체생성 방식의 문제점
- 객체 내부에서 사용되는 메서드나 속성이 중복될 가능성이 높다 ⇒유지보수가 어려워 질수 있다
const person1 = {
name: 'John',
age: 30,
getFullName: function() {
return this.name;
}
};
const person2 = {
name: 'Jane',
age: 25,
getFullName: function() {
return this.name;
}
};
- 다른 객체를 상속받을수 없다(단하나의 객체만생성) ⇒동일한 프로퍼티를 갖는 객체를 생성할 때 매번 같은 프로퍼티를 기술해야한다
- 객체 리터럴 내부에서 선언된 변수는 전역 변수로 취급되어 객체 리터럴 외부에서도 접근할 수 있다 ⇒의도하지 않는 변수 충돌을 유발해 디버깅이 어려워진다
생성자 함수에 의한 객체 생성 방식의 장점
- 인스턴스를 생성하기 위한 템플릿처럼 생성자 함수를 사용하여 프로퍼티 구조가 동일한 객체 여러개를 간편하게 생성 할수 있다
- 생성자 함수에서 사용하는 기능을 활용 가능함
⇒생성자 함수를 사용하면 this를 활용하여 객체의 프로퍼티를 초기화할 수 있다. 또한, 생성자 함수에서 제공하는 다양한 기능들을 활용하여 객체를 더욱 다양하게 구현할 수 있다. - new 연산자와 함께 호출하면 해당 함수는 생성자 함수로 동작 ⇒만약 new 연산자와 함께 생성자 함수를 호출하지 않으면 생성자 함수가 아니라 일반함수로 동작
생성자 함수의 인스턴스 생성과정
인스턴스를 생성하는 것과 생성된 인스턴스를 초기화(인스턴스 프로퍼티 추가및 초기값 할당) 하는것
- 인스턴스 생성과 this 바인딩
⇒생성자 함수 내부에서 this는 새로운 객체를 참조한다
- 인스턴스 초기화
생성자 함수에서 인스턴스를 생성한후 생성된 인스터스에 대해 프로퍼티 값을 할당하거나 메소드를 호출하여 초기값을 설정하는 작업 ⇒this에 바인딩되어 있는 인스턴스를 초기화 ,인스턴스를 초기하지 않으면 생성된 인스턴스는 undefined나 null 등의 값으로 초기화
- 인스턴스 반환
**return**문을 사용하여 명시적으로 객체를 반환하는 경우와 그렇지 않은 경우가 있다
-명시적으로 객체를 반환하는 경우: **return**문에 객체를 명시적으로 반환 ⇒반환되는 객체는 생성자 함수가 생성한 인스터스가 아니라면 생성자 함수가 생성한 인스턴스 무시
function Person(name) {
this.name = name;
return {age: 20};
}
const person = new Person('Tom');
console.log(person); // {age: 20}
-명시적으로 객체를 반환하지 않는 경우: **return**문이 없거나, **return**문에 아무것도 명시되어 있지 않다⇒생성자 함수가 생성한 인스턴스가 반환
function Person(name) {
this.name = name;
}
const person = new Person('Tom');
console.log(person); // Person {name: 'Tom'}
-**return**문에 원시값을 명시하는 경우: 원시값이 명시 되었더라도 반환되는 값은 생성자 함수가 생성한 인스턴스가 반환
function Person(name) {
this.name = name;
return 'Hello, world!';
}
const person = new Person('Tom');
console.log(person); // Person {name: 'Tom'}
-**return**문에 객체가 아닌 다른 객체지향 개념인 **this**를 명시하는 경우: 생성자 함수가 생성한 인스턴스가 반환
function Person(name) {
this.name = name;
return this;
}
const person = new Person('Tom');
console.log(person); // Person {name: 'Tom'}
내부 메서드 [call]과 [construct]
함수와 클래스의 동작 방식을 결정하는 중요한 메서드이다
- [call] 메서드는 함수 객체에 대해 호출 연산자 ()가 사용될 때 실행되는 내부 메서드 ⇒함수가 실행될 때 인자를 전달받고 결과값을 반환
function myFunction(a, b) {
return a + b;
}
myFunction(1, 2); // 3
- [construct] 메서드는 클래스 객체에 대해 new 연산자가 사용될 때 실행되는 내부 메서드
⇒새로운 객체를 생성하고 초기화한 후 반환 class MyClass { constructor(a, b) { this.a = a; this.b = b; } } const myObject = new MyClass(1, 2); console.log(myObject); // {a: 1, b: 2}
constructor 와 non-constructor의 구분
객체 생성 방식에 따라 구분된다
- constructor는 new 연산자와 함께 호출 가능한 함수를 의미 ⇒일반적인 함수 선언문과 함수 표현식, 그리고 ES6에서 도입된 class 문법
// 함수 선언문
function Person(name, age) {
this.name = name;
this.age = age;
}
const person1 = new Person('John', 30);
console.log(person1); // Person { name: 'John', age: 30 }
// 함수 표현식
const Animal = function(name, species) {
this.name = name;
this.species = species;
}
const animal1 = new Animal('Dog', 'Mammal');
console.log(animal1); // Animal { name: 'Dog', species: 'Mammal' }
// 클래스
class Car {
constructor(make, model) {
this.make = make;
this.model = model;
}
}
const car1 = new Car('Toyota', 'Corolla');
console.log(car1); // Car { make: 'Toyota', model: 'Corolla' }
- non-constructor는 new 연산자와 함께 호출할 수 없는 함수를 의미 ⇒this를 사용하지 않거나, 객체를 반환하지 않는다 ,화살표 함수가 있다
const sum = (a, b) => a + b;
const result = sum(1, 2);
console.log(result); // 3
const hello = () => console.log('Hello');
hello(); // Hello
화살표 함수는 this를 바인딩하지 않으며, 객체를 생성하지 않는다,new 연산자와 함께 사용할 수 없다
new 연산자
constructor 함수를 호출하고, constructor 함수가 반환하는 객체를 생성하여 반환 ⇒call이 호출되는게 아니다
new 연산자 없이 생성자 함수를 호출하면 일반함수로 호출 ⇒constructor가 호출되는게 아니라 call 이 호출된다
new.tartget
- constructor 함수 내부에서 다른 constructor 함수를 호출할 때, new.target을 사용하여 호출된 함수가 constructor 함수인지 확인할 수 있다
⇒호출된 함수가 constructor 함수인지 확인하고, 올바른 클래스의 constructor 함수를 호출
class Animal {
constructor() {
console.log(new.target); // Animal
}
}
class Dog extends Animal {
constructor() {
super();
console.log(new.target); // Dog
}
}
const animal = new Animal(); // Animal
const dog = new Dog(); // Animal, Dog
- new 연산자를 사용하지 않고 constructor 함수를 호출하면, new.target은 undefined가 된다
⇒new 연산자를 사용하여 호출되었는지 확인할 수 있다
function Person(name, age) { if (!new.target) { throw new Error('Person must be called with new'); } this.name = name; this.age = age; } const person1 = new Person('John', 30); console.log(person1); // Person { name: 'John', age: 30 } // const person2 = Person('John', 30); // Error: Person must be called with new