개발을 하면서 Class
에 대한 개념을 겉핥기 식으로만 알고 개발을하니 스스로의 문제점들을 발견했다.
Constructor
가 뭐고 Class
를 대체 왜 사용하는지 이런 것들이 궁금해서 예전에 정리했던 것들을 잊은 채 아무것도 몰랐던 그때로 돌아가 한번 다시 알아보려고 한다.
JavaScript ES6의 Class
는 Java와 비슷하게 객체 지향적으로 표현하기 위해서 추가가 되었다. ES5이전에는 Class가 없었지만 ES5에도 Prototype 문법으로 Class를 비슷하게 구현해왔다.
하지만 ES6로 넘어오면서 Java의 Class와 비슷한 구조를 갖게 되었다. 비슷한 구조를 갖게 되었을 뿐 내부적으로는 Prototype 방식으로 작동이 된다.
그럼 Prototype
방식과 Class
방식의 차이를 알아보기 위해서 간단하게 보려고 한다.
// Prototype
// 생성자
function Person({ name, age }) {
this.name = name;
this.age = age;
}
Person.prototype.introduce = function() {
return `Hello, My name is ${this.name}.`;
}
const person = new Person({ name: "Jack", age: 25 });
console.log(person.introduce());
// Class
class Person {
constructor({name, age}) {
this.name = name;
this.age = age;
}
introduce() {
return `Hello, My name is ${this.name}.`;
}
}
const person = new Person({ name: "Jack", age: 25 });
console.log(person.introduce());
Prototype
과 Class
는 같은 결과를 출력한다. 문법의 생김새는 다르지만 로직은 같은 구조로 동작을한다.
constructor
는 instance
를 생성하며 class field를 초기화하기 위한 특수 method다.
constructor
는 class
안에 한 개만 존재할 수 있으며, 한 개 이상일 경우 Syntax Error
가 발생한다.
class
의 field
는 constructor
반드시 내부에서 선언과 초기화가 이루어진다.
constructor
내부에 선언한 class field
는 class
가 생성할 instance
에 binding
이 된다.
class person {
height = 180; // instance 변수 선언
// constructor의 이름은 변경 불가
// this는 class가 생성할 instance를 나타냄
constructor(name, age) {
this.name = name;
this.age = age;
}
}
const person = new Person("Jack", 25);
console.log(person.name); // Jack
console.log(person.age); // 25
console.log(person.height); // 180
다른 언어의 Class
와는 다르게 JavaScript
의 Class
에서는 Instance
변수를 반드시 지정하지 않고 Constructor
를 통해서 this.변수
로 자동 생성을 할 수 있다.
Class의 Method 정의는 객체 리터럴에서 사용하던 방법과 비슷하게 사용한다.
class Calculator {
add(x, y) {
return x + y;
}
subtract(x, y) {
return x - y;
}
}
const calc = new Calculator();
calc.add(1, 1); // 2
객체 리터럴과 비슷하므로 임의의 표현식을 대괄호안에 method 이름을 지정할 수 있다.
const method = "introduce";
class Person {
constructor({ name, age }) {
this.name = name;
this.age = age;
}
[method]() {
return `Hello, My name is ${this.name}.`;
}
}
console.log(new Person({ name: "Jack", age: 25 }).introduce());
정적 method는 class
의 instance
가 아닌 class
이름으로 곧바로 호출하는 method다.
static
keyword를 method 이름 앞에 붙여주면 이 method는 정적 method가 된다.
예시로 랜덤값을 얻기 위할 떄 Math.random()
을 사용하듯 new Math()
없이 곧바로 class
이름에 method
이름을 호출해서 사용하는 것이 random method
가 static으로 되어 있어서다.
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
static static_name - "STATIC";
getName() {
return this.name;
}
static static_getName() {
return this.static_name;
}
}
const person = new Person({ name: "ian", age: 25 })'
person.getName(); // ian
Person.static_getName(); // STATIC
Class
상속을 통해서 하나의 class
기능을 다른 class
에서 재사용을 할 수 있다.
extends는 class를 다른 class의 하위 class로 만들기 위해 사용된다.
class Parent {
}
class Child extends Parent {
}
위 코드를 보면 extends를 이용해서 Child
class가 Parent
class를 상속했다.
이러한 관계를 “부모 class - 자식 class” or ‘’superclass - subclass” 관계라고 한다.
따라서 어떤 class A가 다른 class B를 상속받게 된다면 아래와 같은 일들이 발생한다.
class Parent {
static staticProp = "staticprop";
static staticMethod() {
return "This is static method";
}
instanceProp = "intanceprop";
instaceMethod() {
return "This is instance method";
}
}
class Child extends Parent {}
// 상속 시 Superclass static 요소 사용 가능
console.log(Child.staticProp);
console.log(Child.staticMethod());
// 상속 시 Superclass의 instance를 사용 가능
const child = new Child();
console.log(child.instanceProp);
console.log(child.instanceMethod());
super의 동작 방식은 아래와 같다.
super
를 함수처럼 호출하게되면 superclass의 생성자가 호출super.prop
과 같이 써서 superclass의 prop 정석 속성에 접근할 수 있다.super.prop
과 같이 써서 superclass prop instance 속성에 접근할 수 있다.super(); // 부모 생성자
super.methodName // 접근
------------------------------------------------------------------------
class Person {
constructor(name, first, second) {
this.name = name;
this.first = first;
this.second = second;
}
sum() {
return (this.first + this.second);
}
}
class Person2 extends Person {
// Override Person
constructor(name, first, second, third) {
// 부모 생성자를 가져와 편하게 사용
super(name, first, second);
this.third = third;
}
sum() {
// 부모 method를 가져와 사용
// 오버로딩 method에서 온전한 부모 method를 사용하고 싶을 떄
return super.sum() + this.third;
}
}
const kim = new Person2('kim', 10, 20, 30);
console.log(kim.sum) // 60
Javascript class의 모든 method는 Public으로 지정되었는데 ES2021부터는 method와 field명 앞에 “#”을 붙이면 Private method와 field 정의가 가능해졌다. (private으로도 사용가능)
class myClass {
// private 변수
#num = 100;
// private method
#privateMethod() {
// Private 변수 호출
console.log(this.#num);
}
publicMethod() {
// Private Method 호출
this.#privateMethod();
}
}
const newClass = new myClass();
newClass.publicMethod(); // 100