무작정 부딪쳐서 React를 공부하는데 필요한 기초적인 ES6 문법을 짚고 넘어가기로 했다.
그 세 번째, Class에 대해서 알아보자.
학습 내용은 Do it! 리액트 프로그래밍 정석 책을 기반으로 진행했다.
객체를 만들기 위한 틀 같은 개념으로 상속이 필요한 변수와 메서드를 정의하여 해당 정보를 가진 객체를 만들 수 있도록 하는 것이다. 하지만 기존 자바스크립트에선 클래스라는 개념이 없기 때문에 prototype
을 사용하여 클래스를 표현한다.
기존 자바스크립트에선 함수를 생성자 형태로 선언하고 상속이 필요한 변수나 함수를 prototype
객체에 할당하여 사용했다.
prototype
객체는new
키워드를 사용해 생성된 객체 안에서this
연산자의 변수나 함수 선언 위치를 참조할 수 있는 요소이다.
// Shape class 작성
function Shape(x, y) {
this.name = 'Shape';
this.move(x, y);
}
// Shape class static 함수 선언
Shape.create = function (x, y) {
return new Shape(x, y);
};
// Shape class 인스턴스 함수 move 선언
Shape.prototype.move = function (x, y) {
this.x = x;
this.y = y;
};
// Shape Class 인스턴스 함수 area 선언
Shape.prototype.area = function (x, y) {
return 0;
};
var s = new Shape(0, 0);
console.log(s.area()); // 0
이렇게 new Shape(0, 0)
을 수행하면 this
객체에 해당하는 변수 및 함수가 prototype
객체에 선언된 변수와 함수를 함께 참조한다. 즉 Shape
클래스에 this.move
와 this.area
함수를 정의하지 않았지만 Shape
객체를 생성할 때 prototype
객체에 정의된 내용까지 참조하여 객체를 생성한다.
// Shape class 상속, Circle class 생성자 정의
function Circle(x, y, radius) {
Shape.call(this, x, y);
this.name = 'Circle';
this.radius = radius;
}
// Circle prototype 객체에 Shape prototype과 area 함수를 담은 객체 덮어씌움
Object.assign(Circle.prototype, Shape.prototype, {
area: function () {
return this.radius * this.radius;
},
});
var c = new Circle(0, 0, 10);
console.log(c.area()); // 100
Circle
클래스는 Shape
의 내장 함수 call()
을 사용하여 Shape
클래스의 생성자를 호출하여 초깃값을 상속 받는다. 함수는 Object.assign()
을 사용하여 부모 클래스의 함수를 상속 받거나 덮어쓸 수 있다. 하지만 이러한 방법은 다른 객체 지향 언어와 달라 가독성이 떨어지고 사용하는데 불편하다. 이제 ES6부터 클래스를 좀 더 편하게 사용할 수 있게 되었다.
ES6부터 class 키워드로 클래스를 정의할 수 있다. 이는 다른 객체 지향 언어와 비슷한 형태로 가독성 부분이 해결되었다.
class Shape {
// Shape class 생성자 정의
constructor(x, y) {
this.name = 'Shape';
this.move(x, y);
}
// Shape class static 함수 선언
static create(x, y) {
return new Shape(x, y);
}
// Shape class 인스턴스 함수 선언
move(x, y) {
this.x = x;
this.y = y;
}
area() {
return 0;
}
}
var s = new Shape(0, 0);
console.log(s.area());
다른 객체 지향 언어의 클래스 정의 방식과 매우 닮았으며 한 블록 안에 생성자 constructor()
를 정의하고 각 함수 move()
와 area()
등 가독성 좋게 정의할 수 있다. 단, 차이점으로 선언을 위한 키워드(var, let, const, ...)
는 사용하지 않는다.
class Circle extends Shape {
constructor(x, y, radius) {
super(x, y);
this.radius = radius;
}
area() {
if (this.radius === 0) return super.area();
return this.radius * this.radius;
}
}
var c = new Circle(0, 0, 10);
console.log(c.area()); // 100
Java와 비슷하게 extends
키워드를 사용하여 부모 클래스를 상속받는다. 그리고 부모 클래스를 참조할 경우 super()
함수를 사용하여 참조한다. 이렇게 부모 클래스의 초깃값을 상속 받거나 자식 클래스에서 함수를 덮어쓰는 등 Java와 비슷하게 작성할 수 있다.