[JS] 프로토타입 상속을 이용한 생성자 함수와 ES6 Class

JunSeok·2024년 1월 1일
0

Javascript

목록 보기
14/16
post-thumbnail

생성자 함수와 class를 통해 프로그래밍적으로 객체를 생성할 수 있다.

생성자 함수

  • 정규 함수와 같지만, 유일한 차이는 반드시 new 연산자를 사용해 호출한다는 것이다.
  • 함수 이름의 첫글자는 대문자여야 한다.
  • 화살표 함수는 고유의 this keyword가 없기 때문에 함수 선언식과 함수 표현식으로만 가능하다. this keyword 정리
  • new 연산자로 생성자 함수를 호출하면 함수 기능뿐만 아니라 그 이상의 일을 한다.
    1. 생성자 함수 타입의 빈 객체를 즉시 생성한다.
    2. 함수가 호출되면, 함수 안의 this keyword가 새로 생성된 객체를 가리킨다. 생성자 함수 내에서 console.log(this) 로 확인해보면 빈 객체가 나온다. (this = {})
    3. 새로 생성된 객체가 생성자 함수의 프로토타입과 연결된다.(아래 예시에서는 객체가 Person.prototype과 연결된다.)
    4. 생성자 함수 내에서는 입력받은 값을 this keyword의 property로 설정한다.
    5. 생성자 함수는 this 객체를 리턴한다.
    6. 리턴된 객체가 바로 생성자 함수로부터 생성된 객체이다.
const Person = function(firstName, lastName) {
	console.log(this); // {}
    this.firstName = firstName;
  	this.lastName = lastName;
}

const oort = new Person(cloud, oort);
// Person {firstName: 'cloud' , lastName: 'oort'}

// oort는 Person의 instance이다.
console.log(oort instanceof Person); // true
  • 자바스크립트에는 전통적인 OOP의 클래스가 없다. 하지만 생성자 함수를 통해 만든 객체를 인스턴스라 한다.
  • 생성자 함수 내에서 property를 받는 것은 좋지만, method를 정의하는 것은 매우 비효율적인 일이다.
    method를 가지고 있는 생성자 함수가 1000개의 인스턴스를 만들면 1000개의 함수 복사본을 만드는 것과 같기 때문에 코드 실행에 최악이다.

    이 문제를 해결하기 위해 prototypal inheritance를 이용한다.

Prototypal Inheritance(프로토타입 상속)

  • 프로토타입 상속은 method를 공유할 때 강점을 드러낸다.
  • 특정 생성자 함수로 생성된 모든 객체는 생성자 함수의 prototype과 연결되어 있다.
  • 그렇기 때문에 생성자 함수를 통해 생성된 객체는 생성자 함수의 prototype에 정의된 모든 property와 method에 접근할 수 있다.

    생성자 함수의 prototype에 method를 정의해서, 생성자 함수와 연결된 객체가 생성자 함수의 prototype에 정의된 method를 끌어당겨 쓰는 것이 프로토타입 상속이다. 코드를 재사용하는 메커니즘이라 할 수 있다.

예시

  • 자바스크립트의 모든 함수(생성자 함수 포함)는 prototype이라는 propery를 자동으로 가지고 있다.
  • 자바스크립트의 모든 객체는 __proto__라는 property를 갖고 있다.
  • new 키워드로 생성자 함수를 생성할 때, 함수 내의 this 키워드가 생성자 함수의 프로토타입과 연결된다고 했고 그 this 키워드가 리턴된다고 했다.
  • 리턴된 this 키워드가 바로 인스턴스이며 인스턴스의 __proto__ property와 생성자 함수의 prototype은 연결되었기 때문에 값이 같다.

    oort.__proto__은 항상 Person.prototype을 가리킨다.

  • 즉 생성자 함수의 property에 method를 한 번만 정의해두면, 그 뒤로 생성된 객체는 생성자 함수의 prototype과 연결된 객체의 __proto__ property를 통해 method를 사용할 수 있다.

프로토타입 체인

  • 생성자 함수로 생성한 객체가 자기 자신에 없는 property 또는 method를 사용할 때, 객체의 프로토타입 즉 생성자 함수의 프로토타입에서 property 또는 method를 찾는다.
  • 생성자 함수의 프로토타입 또한 객체이기 때문에 프로토타입을 가지고 있다.
  • 프로토타입으로 null을 가진 객체에 도달할 때까지 이 연결은 계속되며 이를 프로토타입 체인이라 한다.

주의할 점

  • 생성자 함수의 prototype이 생성자 함수의 프로토타입은 아니라는 점을 유의해야 한다.
  • 즉 생성자 함수의 prototype property는 생성자 함수의 프로토타입이 아니라 생성자 함수를 통해 생성된 모든 객체와 연결된 프로토타입이다.
  • 그래서 생성자 함수로 만든 모든 인스턴스 객체의 __proto__ property는 생성자 함수의 prototype property와 같은 값을 가진다.
  • 생성자 함수의 prototype의 constructor가 생성자 함수와 같다.
  • 모든 객체는 프로토타입을 가지고 있기 때문에 객체 타입의 생성자 함수의 prototype도 프로토타입이 있는데, 바로 Object.prototype이다. 이 Object는 프로토타입 체인의 최상단이기 때문에 Object의 프로토타입은 null값을 가진다.

생성자 함수와 ES6 class

  • 자바스크립트의 ES6 class는 전통적인 OOP의 클래스처럼 동작하지 않으며, 생성자 함수의 syntax sugar일 뿐이다.
  • 내부적으로는 생성자 함수와 class 모두 동일하게 프로토타입 상속을 구현하지만 다른 프로그래밍 언어를 사용하는 사람들이 이해하기 쉽도록 class라는 synstax sugar로 표현한 것일 뿐이다.
    그렇기 때문에 class는 단지 특별한 형식의 함수일 뿐이다.

차이

  • 생성자 함수는 property를 정의할 때, 생성자 함수 안에 정의한다.
  • class는 constructor 함수안에 정의한다.

    하지만 둘 다 method는 그 밖에서 정의한다. 이는 위에서 말한 프로토타입 상속과 방법이 일치한다.

  • method를 생성자 함수에서 정의하는 것은 비효율적이기 때문에
    => method를 생성자 함수의 prototype에 직접 정의하는 것
    => class를 사용할 때 method를 constructor 함수 바깥에서 정의하는 것은 프로토타입 상속을 이용하는 원리가 같지만 문법적으로만 다르게 보일 뿐인 syntax sugar이다.
const Person = function(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}
// method를 생성자 함수의 prototype에 직접 정의하는 것
Person.prototype.hello = function() {
    console.log('hi')
}

const oort = new Person('cloud', 'oort');

// 위 방법과 아래 방법은 원리상 같지만 문법적으로만 다른 systax sugar임을 잘 보여준다.
class ClassPerson {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
	// class를 사용할 때 method를 constructor 함수 바깥에서 정의하는 것
    hello() {
        console.log('hi')
    }
}

const oort = new ClassPerson('cloud', 'oort');

정리

  • 생성자 함수와 class는 모두 같은 원리로 객체를 생성한다.
  • 생성자 함수는 method를 정의할 때 prototype 속성에 직접 정의해야 했지만, class의 경우 constructor 함수 바깥에만 정의하면 클래스의 prototype 속성에 자동으로 정의된다.
  • 생성자 함수보다 클래스의 사용이 훨씬 편하지만, 그 이전에 생성자 함수, 프로토타입, 프로토타입 체인을 잘 이해하는 것이 필요하다.

즉 생성자 함수와 클래스 모두 사용해도 되지만 프로토타입에 대한 완전한 이해가 뒤따라야 한다.

참조

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/new
https://poiemaweb.com/js-object-oriented-programming
https://www.udemy.com/course/the-complete-javascript-course/

profile
최선을 다한다는 것은 할 수 있는 한 가장 핵심을 향한다는 것

0개의 댓글