class vs prototype[미완]

woolim park·2021년 3월 26일
1

자바스크립트는 프로토타입기반 언어다.

그래서 어쩌라고?
class 기반으로 코딩하는게 더 익숙하고 편한걸.

ES6의 class문법이 등장하면서 상속을 구현하기 위해 prototype chaining 을 써야할 필요가 없어졌다. 사실 ES6에서 class가 등장한 배경에는 prototype OOP 보다는 class OOP에 익숙한 개발자들이 많기 때문이다.

class OOP 방법론의 세뇌된 개발자의 한 사람으로서 JS가 원래 추구하고자 했던 prototype 기반 프로그래밍이 무엇인지 궁금해졌다. 어쩌면 우리는 class 가 익숙하다고 JS가 가진 본래의 가치를 떨어뜨리는게 아닐까라는 순수한 의구심이 든 것이다.

불변 class, 가변 prototype

클래스는 설계도라서 한번 만든 설계도는 도중에 바뀌는 일이 없다. class 블록 안에 내가 적은 코드는 프로그램이 시작되면 runtime에 바뀌는 일이 없고, 같은 설계도에서 찍어낸 인스턴스는 실행 중에 property나 methods 를 추가하지 않는 한 동일한 형태를 가진다.

반면 prototype 기반 언어는 객체가 곧 설계도가 된다. 객체는 runtime 중에 동적으로 속성추가가 가능하므로 동적인 설계도가 가능하다.

var cat = {leg: 4}
var metamon = {};

Object.setPrototypeOf(metamon, cat);
console.log(metamon.leg); // 4

// prototype 객체 cat에 메소드 추가
cat.speak = function() { return "Miew" }
console.log(metamon.speak()); // Miew

prototype 객체를 다른 prototype 객체로 바꿔치기 할 수도 있다.

var cat = { speak() { return "Miew" } };
var human = { speak() { return "Hello" } };
var metamon = {};

Object.setPrototypeOf(metamon, cat); // 메타몽의 프로토타입을 cat으로
console.log(metamon.speak()); // Miew

Object.setPrototypeOf(metamon, human); // 메타몽의 프로토타입을 human으로
console.log(metamon.speak()); // Hello

class 상속 vs prototype 상속

class 에서 상속은 부모 클래스와 자식 클래스간의 관계를 말한다.
prototype 에서의 상속은 prototype 객체와 그것을 상속하는 객체와의 관계를 말한다.

function Shape() {
  this.x = 0;
  this.y = 0;
};
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved to : ', this.x, this.y);
};
var shape = new Shape();
shape.move(1, 3);

new 카워드를 생성자 함수 앞에서 사용하는 건 사실 다음과 같은 일이 벌어지는 것이다.

// 이건 사실
var shape = new Shape();

// 이것과 같다.
var shape = new Object(); // 빈 객체를 생성
Object.setPrototypeOf(shape, Shape.prototype); // 상속할 프로토타입 설정
Shape.call(shape); // shape객체를 this로 생성자함수를 실행

보면 알겠지만 prototype 상속은 class 로 따지면 constructor 단계에서 일어나는 일일 뿐이다. 새로운 객체를 생성할때 class 방식은 하나의 클래스에서 바로 인스턴스가 나오지만, prototype 방식은 prototype 객체 참조를 상속한 후에 인스턴스를 만드는 것이다.

class 의 부모 자식 상속관계를 구현하려면 prototype chaining 을 사용해야한다.

prototype chaining

Object.create(obj) 는 obj 객체를 prototype 으로 참조하는 새로운 객체를 만든다.

// Shape - superclass
function Shape() {
  this.x = 0;
  this.y = 0;
}
Shape.prototype.move = function(x, y) {
  this.x += x;
  this.y += y;
  console.info('Shape moved to : ', this.x, this.y);
};

// Rectangle - subclass
function Rectangle() {
  Shape.call(this); // 부모 생성자 실행
}

// subclass extends superclass
Rectangle.prototype = Object.create(Shape.prototype);

//If you don't set Rectangle.prototype.constructor to Rectangle,
//it will take the prototype.constructor of Shape (parent).
//To avoid that, we set the prototype.constructor to Rectangle (child).
Rectangle.prototype.constructor = Rectangle;

var rect = new Rectangle();

console.log('Is rect an instance of Rectangle?', rect instanceof Rectangle); // true
console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
rect.move(1, 1); // Outputs, 'SShape moved to : 1, 1'

Mixin

const distortion = { distortion: 1 };
const volume = { volume: 1 };
const cabinet = { cabinet: 'maple' };
const lowCut = { lowCut: 1 };
const inputLevel = { inputLevel: 1 };

const GuitarAmp = (options) => {
  return Object.assign({}, distortion, volume, cabinet, options);
};

const BassAmp = (options) => {
  return Object.assign({}, lowCut, volume, cabinet, options);
};

const ChannelStrip = (options) => {
  return Object.assign({}, inputLevel, lowCut, volume, options);
};

참고자료

profile
Javascript Developer

0개의 댓글