코드노트

자바스크립트 Object 객체 생성자 함수 본문

Code note/자바스크립트

자바스크립트 Object 객체 생성자 함수

코드노트 2022. 12. 14. 21:16

Object 생성자 함수

- new 연산자와 Object 생성자 함수를 호출하게 되면 빈 객체를 생성하여 반환

- 빈 객체를 생성한 후 프로퍼티, 메서드를 추가해 객체를 완성

- 생성자 함수에 의해 생성된 객체를 인스턴스(instance)라 한다.

const tranvel = new Object();

tranvel.first = "곽튜브";
tranvel.hello = function () {
  console.log(`Hi! ${this.first}`);
};

console.log(tranvel); // { first: '곽튜브', hello: [Function] }
tranvel.hello(); // Hi! 곽튜브

- new 연산자로 객체를 생성하고  프로퍼티를 추가할 수 있다.

- Object 외에도 String, Number, Boolean, Function, Array, Date, RegExp, promise 등등 빌트인 생성자 함수를 만들 수도 있다.

 

그러나 Object 생성자 함수로 하는것 보단, 객체리터럴 방식으로 하는게 더 직관적이고 간편하게 사용할 수 있다.

그러면 생성자 함수는 어떻게 쓰일까?


만약 같은 값이나 메서드를  가진 객체를 사용하는데 여러개의 객체를 만들어야 한다면?

같은 함수를 반복하여 작성하지 않고 생성자 함수를 사용하여 간편하게 생성하면 된다.

function Add(num) {
  this.num = num;
  this.getAdd = function () {
    return num + this.num;
  };
}
const one = new Add(1);
const two = new Add(2);

console.log(one.getAdd()); // 2
console.log(two.getAdd()); // 4

- 함수는 하나만 생성하고 num값을 가진 객체를 만들어준다.

- 생성자 함수를 사용해서 프로퍼티 구조가 같은 객체를 여러개 만들더라도 간편하게 만들 수 있다.


여기서 this 는?

- 객체 자신의 프로퍼티 또는 메서드를 참조하는 변수 이다.

- this가 가리키는 값, this 바인딩은 함수 호출 방식에 따라서 동적으로 결정

함수 호출 방식 this가 가리키는 값(this 바인딩)
일반 함수로서 호출 전역 객체
메서드로서 호출 메서드를 호출한 객체(마침표 앞의 객체)
생성자 함수로서 호출 생성자 함수가 생성할 인스턴스

▶ 일반함수에서 사용하면 전역window를 가르킨다.

▶ 메서드로 호출하게 되면 호출한 객체를 가르킨다.

▶ 생성자 함수가 생성하는 인스턴스(생성된 객체)를 가르킨다.


생성자 함수는 빈객체를 만들거나 반환하는 것을 자바스크립트가 암묵적으로 처리한다.

- 인스턴스 생성 및 반환을 암묵적으로 처리

* 생성자 함수에서는 return 문을 생략 해야한다! 그렇지 않으면 생성자 함수의 기본 동작을 훼손한다.

- 메서드 외에 returm은 사용하지 말자!

== this가 반환되지 않고, return 문에 명시한 객체가 반환된다.

 

 


내부 메서드 [[call]], [[construct]]

- 일반 함수도 new 연산자를 통해 생성자 함수로 호출할 수 있다.

- 함수는 객체이기 때문에 일반 객체와 동일하게 동작 한다.

- 그러나 함수는 일반 객체와는 다르다. 일반 객체는 호출할 수 없지만, 함수는 호출이 가능하다.

 

* 함수 객체는 함수로 동작하기 위한 내부 슬롯, 내부 메서드를 가지고 있다.

내부 슬롯 : [[ Environment ]], [[ FormalParameters ]]

내부 메서드 : [[ Call ]], [[ Construct ]]

 

- 함수가 일반 함수로 호출 되면 함수 객체의 내부 메서드 [[ Call ]]이 호출

- new 연산자, 생성자 함수가 호출 되면 내부 메서드 [[ Construct ]]가 호출

 

[[ Call ]]을 갖는 함수 객체  callable

[[ Construct ]]를 갖는 함수 객체 constructor

[[ Construct ]]를 갖지 않는 함수 객체non-constructor

callable : 호출할 수 있는 객체, 함수

constructor : 생성자 함수로서 호출할 수 있는 함수

non-constructor : 객체를 생성자 함수로 호출할 수 없는 함수

 

- 호출할 수 없는 객체는 함수 객체가 아니다.

- 호출이 가능한 함수 객체는 반드시 callable이어야 한다.

** 모든 함수 객체는 내부 메서드 [[ call ]]을 가지고 있기 때문에 호출 가능

*** 그 함수 객체중 모두 [[ construct ]]를 갖는건 아니다.

 

그렇기 때문에 함수 객체는 모두 호출할 수 있지만, 생성자 함수로서 호출할 수는 없다.


그럼 constructor, non-constructor은 어떻게 구분할까?

 

- 함수 정의를 평가하고 함수 객체를 생성할 때 함수 정의 방식에 따라서 함수를 구분한다.

▶ constructor

- 함수 선언문, 함수 표현식, 클래스

 non-constructor

- 메서드, 화살표 함수

 

여기서 알 수 있는 TIP

- 함수를 프로퍼티 값으로 사용하면 일반적으로 메서드로 통칭

* 함수가 할당된 위치가 아닌 일반 함수, 함수 선언문, 함수 표현식으로 정의된 함수만 constructor

* 반대로 생각하면 축약 및 화살표 함수로 생성한 함수는 메서드다.

 

new 연산자로 호출하는 함수는 constructor 이어야 한다.


- 어렵게 생각하지말고 재사용할 함수는 첫 문자를 대문자로!

- this 바인딩

- new를 붙여 실행하면 된다.

function Person(name) {
// 암묵적으로 인스턴스 생성 및 this에 바인딩 this = {}
  this.name = name;
  this.sayHello = function () {
    console.log(`내 이름은 ${this.name} 입니다.`);
  };
}
const person1 = new Person("곽튜브");
person1.sayHello(); // 내 이름은 곽튜브 입니다.

new.target

* new.target은 this와 유사하게 constructor인 모든 함수 내부에서 암묵적인 지역 변수와 같이 사용되며, 메타 프로퍼티라 부른다.

function Person(name) {
  this.name = name;
  this.sayHello = function () {
    console.log(`내 이름은 ${this.name} 입니다.`);
  };
}

console.log(Person()); // undefined
console.log(new Person()); // Person { name: undefined, sayHello: [Function] }

- 간단하게 보면 new.target은 함수가 new연산자로 호출되었는지 아닌지 알 수 있다.

- 일반 함수로 호출이 되었다면 Undefined를 반환, new와 함께 호출 되었다면 함수를 반환


function Person(name) {
  if (!new.target) {
    return new Person(name);
  }
  this.name = name;
  this.sayHello = function () {
    console.log(`내 이름은 ${this.name} 입니다.`);
  };
}

console.log(Person()); // Person { name: undefined, sayHello: [Function] }
console.log(new Person()); // Person { name: undefined, sayHello: [Function] }

- 위와 같은 코드이지만 if문을 통해서 new.target을 통해서 undefined가 나오지 않게 new를 붙여 호출하도록 해준다.

 

- 이렇게 하면 new 연산자를 사용하지 않아도 함수 호출시 new연산자로 사용이 가능하다.

 

그러나 코드를 보고 new가 붙어 있으면 생성자함수인것을 바로 알 수 있듯이 좋아 보이지는 않는다.