Prototype - 생성자 함수

GY·2021년 11월 2일
0

[JS] 개념 정리

목록 보기
25/32
post-thumbnail
post-custom-banner

Constructor Function 생성자 함수

new키워드와 함께 실행 하는 함수를 생성자 함수라고 한다.
생성자 함수는 일반적으로 함수명을 '명사'로 짓고, 함수명의 첫 글자를 대문자로 표기한다.

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

const person1 = new Person("person1", 37);

console.log(person1); // Person {name: 'person1', age: 37}

생성자 함수의 기본값 : this

자바스크립트에서 함수의 리턴값이 명시되지 않는다면 기본적으로 undefined가 반환된다.
하지만 아래 예제에서는 return값이 없는 함수임에도 특정객체가 반환되어 person1이라는 변수에 담기게 돈다.

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

const person1 = new Person("person1", 37);

console.log(person1); // Person {name: 'person1', age: 37}

왜 이럴까?

생성자 함수의 기본 반환값은 this이기 때문이다.
또한 생성자 함수는 일반적으로 반환값을 명시하지 않는다.

자바스크립트의 객체 생성과정

모든 자바스크립트 객체는 생성자 함수를 이용해 만들어진다고 볼 수 있다.

아래와 같이 객체를 생성하는 방법은,

const obj = {};
const arr = [];
const func = function () {};

아래 방식과 동일하다.

const obj = new Object();
const arr = new Array();
const func = new Function();

여기서 Object, Array, Function은 js에 내장된 생성자 함수로, 첫번째 처럼 간결하게 작성해도 두번째와 같이 생성자함수를 이용해 만드는 것과 동일하게 객체를 생성한다.

모든 함수에는 prototype 속성이 내장되어 있다.

모든 함수는 객체이며, key와 value를 가질 수 있다.

각 함수가 소유한 prototype객체는 해당 함수가 생성자 함수로서 실행될 때 특정 역할을 하도록 설계되어 있다.

function foo() {
  console.log("I am foo.");
}

const something = new foo();

이 예시에서 something이라는 변수에는 foo함수를 생성자 함수로 실행한 반환값, 즉 빈 객체가 담겨져있다.

console.log(something.hello); // undefined

그렇다면 콘솔 출력문에서 존재하지 않는 속성을 접근하기 때문에 undefined가 출력된다.

foo.prototype.hello = "Hello, World";

console.log(something.hello); // Hello, World

두번째 콘솔 출력문에서는 Hello, World가 출력된다.

이것을 이해하기 위해서는 인스턴스에 대해 알아보자.

Instance

생성자 함수가 반환하는 빈 객체를 Instance (인스턴스)라고 부른다.

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

const person1 = new Person("person1");

예를 들어, person1은 person의 인스턴스이다.

Instance & Prototype

모든 인스턴스 객체는 해당 객체의 프로토타입에 존재하는 속성과 메소드에 접근해 사용할 수 있다.

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

Person.prototype.age = 30;

const person1 = new Person("person1");

console.log(person1.age); // 30

함수는 생성될 때 고유의 프로토타입 객체와 함께 생성된다.

생성자 함수 Person은 Person.prototype 객체와 함께 생성된다.

person1은 Person의 인스턴스로,
Person 생성자 함수를 통해 만들어졌기 때문에 Person.prototype에 존재하는 속성을 사용할 수 있다.

따라서 person.age를 출력하면 Person.prototype.age의 값을 출력한다.

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

function Animal(breed) {
  this.breed = breed;
}

Animal.prototype.age = 10;

const person1 = new Person("person1");

console.log(person1.age); // undefined

여기서 person1은 Person의 인스턴스이므로 Peron의 프로토타입을 상속한다. Animal의 프로토타입을 상속하지는 않으므로, Animal.prototype.age = 10가 있더라도 person1.age에는 아무런 영향을 받지 않는다. 따라서 undefined가 출력된다.

프로토 타입의 생성시점

프로토타입은 생성자 함수가 생성되는 시점에 더불어 생성된다.
생성자 함수는 두 가지로 구분할 수 있다.

  • 사용자 정의 생성자 함수 (사용자 정의)
  • 빌트인 생성자 함수 (js 기본제공)

각 생성자 함수 종류별 생성 시점에 대한 내용 추가 예정

객체 생성 방식과 프로토타입의 결정

객체 생성 방법은 다음과 같다.

  • 객체 리터럴
  • Object 생성자 함수
  • 생성자 함수
  • Object.create 메서드
  • 클래스

모든 객체는 추상연산 OrdinaryObjectCreate에 의해 생성된다는 공통점이 있다.

추상연산 OrdinaryObjectCreate

필수적으로 자신이 생성할 객체의 프로토타입을 인수로 전달받는다.
빈 객체를 생성한 후 객체에 추가할 프로퍼티 목록이 인수로 전달된 경우에 프로퍼티를 객체에 추가한다. 그리고 인수로 전달받은 프로토타입을 자신이 생성한 객체의 [[prototype]] 내부 슬롯에 할당한 다음, 생성한 객체를 반환한다.

즉, 프로토타입은 추상연산 OrdinaryObjectCreate에 전달되는 인수에 의해 결정되는데, 이 인수는 객체가 생성되는 시점에 객체 생성 방식에 의해 결정된다.

생성방식 -1) 객체리터럴

객체리터럴을 평가해 객체를 생성할 때 js엔진이 추상연산을 호출한다. 추상연산 OrdinaryObjectCreate에 전달되는 프로토타입은 Object.prototype으로,
객체 리터럴에 의해 생성되는 객체의 프로토타입은 Object.prototype이다.따라서 Object.prototype의 프로퍼티와 메서드를 상속받아 사용할 수 있다.

생성방식 -2) Object 생성자 함수

Object 생성자 함수를 호출하면 똑같이 추상연산은 Object.prototype을 전달받는다.

생성방식 -3) 생성자 함수

생성자 함수를 호출하여 인스턴스를 생성하면
추상연산에 전달되는 프로토타입 (=생성자 함수에 의해 생성되는 객체의 프로토타입)은 생성자 함수의 prototype 프로퍼티에 바인딩되어 있는 객체다. (constructor property 참고)

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

const me = new Person('Lee');

사용자 정의 생성자 함수 Person과 더불어 생성된 프로토타입 Person.prototype의 프로퍼티는 constructor뿐이다.

생성방식 -4) Object.create

Object.create메서드는 명시적으로 프로토타입을 지정하여 새로운 객체를 생성한다. (다른 객체 생성방식과 마찬가지로 추상연산)

constructor property

모든 프로토 타입은 constructor프로퍼티를 갖는다. 이것은 prototype프로퍼티로 자신을 참조하고 있는 생성자 함수를 가리킨다.
constructor프로퍼티는 생성자 함수가 생성될 때 연결된다.
이 때 constructor 프로퍼티가 가리키는 생성자 함수는 인스턴스를 생성한 생성자 함수다.

프로토타입 체인

자바스크립트는 객체의 프로퍼티에 접근하려고 할 때 해당 객체에 접근하려는 프로퍼티가 없다면 [[Prototype] 내부 슬롯의 참조를 따라 부모역할을 하는 프로토타입의 프로퍼티를 순차적으로 검색한다. 이것을 프로토타입 체인이라 한다.

프로토타입 체인은 자바스크립트가 객체지향 프로그래밍의 상속을 구현하는 메커니즘이다.

프로토타입 체인 vs 스코프 체인

  • 프로토타입 체인: 상속과 프로퍼티 검색을 위한 메커니즘
  • 스코프 체인: 식별자 검색을 위한 메커니즘

프로퍼티 오버라이딩, 섀도잉

오버라이딩 overriding

프로토타입 프로퍼티와 같은 이름의 프로퍼티를 인스턴스에 추가하면 인스턴스 프로퍼티로 추가한다.
이 때, 인스턴스 메서드 는 프로토타입 메서드를 오버라이딩했다고 한다.

섀도잉 shadowing

이와 같이 상속관계에 의해 프로퍼티가 가려지는 현상을 프로퍼티 섀도잉이라고 한다.

직접 상속

매개변수

@param {Object} prototype
@param {Object} [propertiesObject]
@return {Object}

Object.create(prototype[, propertiesObject])
  • 첫번째 매개변수: 생성할 객체의 프로토타입으로 지정할 객체
  • 두번째 매개변수(optional): 생성할 객체의 프로퍼티 키와 프로퍼티 디스크립터 객체로 이뤄진 객체

Object.create메서드는 첫번째 매개변수에 전달한 객체의 프로토타입 체인에 속하는 객체를 생성한다.
즉, 객체를 생성하면서 직접적으로 상속을 구현한다.

이렇게 했을 때 장점은 무엇일까?

  • new 연산자 없이 객체 생성
  • 프로토타입을 지정하면서 객체 생성
  • 객체 리터럴에 의해 생성된 객체도 상속받을 수 있음
profile
Why?에서 시작해 How를 찾는 과정을 좋아합니다. 그 고민과 성장의 과정을 꾸준히 기록하고자 합니다.
post-custom-banner

0개의 댓글