클래스 바디의 필드와 메서드
- 클래스 바디란
{}
내부의 요소들을 말한다. - 클래스 바디엔 대표적으로 상태를 저장하는 필드와 상태를 이용해 동작을 수행하는 메서드가 있다.
클래스의 바디에 올 수 있는 요소의 경우의 수
- 종류:
Getter
,Setter
,Method
,Field
- 위치:
Static
,Instance
- 접근:
Public
,Private
클래스의 바디에 오는 요소는 위 3가지를 모두 가져야 한다. 총 16가지 조합이 가능하다.
클래스에만 있는 특별한 것들
클래스 필드 추가하기
class ExampleClass {
constructor() {
this.field = 1;
}
}
const c = new ExampleClass();
console.log(c.field); // 1
- 예전엔 생성자에서
this.fieldName = fieldValue
와 같은 문법으로 필드를 추가해야 했다.
class ExampleClass {
field = 1;
}
const c = new ExampleClass();
console.log(c.field); // 1
- 이제는 위와 같은 문법으로도 추가 가능하다.
- 기본 할당은 자연적으로 구성, 쓰기, 열거를 지원한다.
클래스 private
필드
class ClassWithPrivateField {
#privateField;
constructor() {
this.#privateField = 42;
}
getPrivateField() {
return this.#privateField;
}
}
const c = new ClassWithPrivateField();
console.log(c.getPrivateField()); // 42
console.log(c.#privateField); // Uncaught SyntaxError: Private field '#privateField' must be declared in an enclosing class
private field
는 클래스 외부에서 접근이 불가능한 필드이다.- 클래스 내부에서만 접근이 가능하다.
class ClassWithPrivateField {
#privateField;
constructor() {
this.#privateField = 42;
this.#randomField = 666; // Uncaught SyntaxError: Private field '#randomField' must be declared in an enclosing class
}
}
private field
는 일반 필드와 다르게 반드시 위에서 먼저 선언 후에 사용해야 한다.
클래스 private
메서드
class ClassWithPrivateMethod {
#privateMethod() {
return "hello world";
}
getPrivateMessage() {
return this.#privateMethod();
}
}
const instance = new ClassWithPrivateMethod();
console.log(instance.getPrivateMessage()); // "hello world"
- 직접 접근할 수는 없지만 클래스 내부에서 접근 가능한 메서드이다.
class ClassWithPrivateAccessor {
#message;
get #decoratedMessage() {
return `✨${this.#message}✨`;
}
set #decoratedMessage(msg) {
this.#message = msg;
}
constructor() {
this.#decoratedMessage = "hello world";
console.log(this.#decoratedMessage);
}
}
new ClassWithPrivateAccessor(); //`✨hello world✨`
private method
역시 접근자로도 사용될 수 있다.
클래스 public static
필드
class ClassWithStaticField {
static staticField = "static field";
}
console.log(ClassWithStaticField.staticField); // "static field"
public static
필드는 인스턴스로 접근하는 것이 아니라 클래스 생성자로 접근할 수 있는 필드를 말한다.- 모든 클래스가 같은 값을 갖는 필드 등을 캐싱해놓으면 유리하다.
class ClassWithStaticField {
static baseStaticField = "base field";
}
class SubClassWithStaticField extends ClassWithStaticField {
static subStaticField = "sub class field";
}
console.log(SubClassWithStaticField.subStaticField); // "sub class field"
console.log(SubClassWithStaticField.baseStaticField); // "base field"
public static
필드도 상속의 대상이다.- 다른 언어에서는 정적 필드에 대한 상속을 지원하지 않으므로 눈여겨볼만하다.
클래스 public static
메서드
class ClassWithStaticMethod {
static baseStaticMethod() {
return "base static method output";
}
}
console.log(ClassWithStaticMethod.baseStaticMethod()); // base static method output
public static
필드 뿐만 아니라 당연히 메서드도 지원한다.
class ClassWithStaticField {
static baseStaticField = "base static field";
static anotherBaseStaticField = this.baseStaticField;
static baseStaticMethod() {
return "base static method output";
}
}
class SubClassWithStaticField extends ClassWithStaticField {
static subStaticField = super.baseStaticMethod();
}
console.log(ClassWithStaticField.anotherBaseStaticField); // "base static field"
console.log(SubClassWithStaticField.subStaticField); // "base static method output"
public static
메서드 역시 상속의 대상이다.- 상속 후에
super
키워드를 통해static method
를 불러올 수도 있다.
class ClassWithStaticMethod {
static staticProperty = "someValue";
static staticMethod() {
return "static method has been called.";
}
static {
console.log("Class static initialization block called");
}
}
// Class static initialization block called
console.log(ClassWithStaticMethod.staticProperty); // "someValue"
console.log(ClassWithStaticMethod.staticMethod()); // "static method has been called."
static
블록은 클래스가 평가되며 자동으로 실행된다.
클래스 메서드 추가
class Color {
constructor(r = 0, g = 0, b = 0) {
this.r = r;
this.g = g;
this.b = b;
}
toString() {
return this.rgb;
}
}
위는 toString()
을 추가하는 예시이다. 이전 ES5 코드에서는 아래와 같이 작성해야 했다.
Color.prototype.toString = function toString() {
return this.rgb;
};
- 클래스 메서드 구문이 더욱 선언적이다.
- 새로운 구문을 이용하면 자연적으로 메서드는
enumerable
하지 않게 추가된다.- 이전엔
Object.defineProperty()
를 이용해야 했다.
- 이전엔
- 새로운 문법을 이용하면 메서드의
prototype
속성에 아무것도 존재하지 않는다. - 이전엔
.prototype.toString = function toString() { ... }
을 이용했으므로 자동으로Object
를 상속하여prototype
에Function.prototype
이 들어있었다.
클래스 정의 방법
// 일반 정의
class Color {}
// 익명 클래스 정의
let Color = class {};
// 클래스 정의를 변수로 참조하기
let C = class Color {};
- 총 3가지의 정의 방법이 있다.
- 클래스 선언은 함수 선언처럼 호이스팅 되지 않는다.
- 임시 데드존과 같이 호이스팅 된다.
let
,const
와 마찬가지로 전역에서 선언해도 전역 객체의 속성이 아니다.
클래스 생성자의 특징
new
키워드를 사용해야만 생성자 호출이 가능하다.- 생성자 함수를 직접 호출하려하면, 오류가 발생한다.
- 사실
Reflect
를 이용하면 호출이 가능하긴 하다.
ES5 에서 함수를 클래스처럼 이용하는 방식은 사실상
new
키워드 없이도 함수호출이 되어 혼란스러운 버그를 초래하기도 했다.this instanceof Color
와 같은 구문을 통해 예외처리를 해주어야만 했다.
Color(); // TypeError: Class constructor Color cannot be invoked without 'new'
클래스 내부 코드의 특징
- 항상 엄격 모드(
"strict mode"
)이다. - 클래스 내부 속성을 정의할 때 세미콜론이나 컴마를 쓰지 않는다.
- 내부 메서드를 선언적이고 간결하게 정의할 수 있다.
- ES5는
Color.prototype.toString = function toString() {...}
와 같은 방식으로 정의해왔다.
- ES5는
이전보다 메모리 효율이 좋다.
// ES2015 `class` 키워드를 이용한 클래스와 메서드 정의
class Color {
print() {
console.log("color");
}
}
var c = new Color();
console.log(typeof c.print.prototype); // undefined
// ES5 `function` 키워드를 이용한 클래스와 메서드 정의
function ColorFunction() {}
const Color2 = ColorFunction;
Color2.prototype.print = function () {
console.log("color");
};
var c2 = new Color2();
console.log(typeof c2.print.prototype); // object
class
키워드를 이용한 클래스 메서드에는prototype
이 안붙어있다.function
키워드를 이용한 클래스 메서드에는prototype
이 붙어있다.
정적 메서드 코드 살펴보기
class Color {
constructor(r = 0, g = 0, b = 0) {
this.r = r;
this.g = g;
this.b = b;
}
get rgb() {
return `rgb(${this.r}, ${this.g}, ${this.b})`;
}
set rgb(value) {
// TODO ...
}
toString() {
return this.rgb;
}
static fromCSS(css) {
const match = /^#?([0-9a-f]{3}|[0-9a-f]{6});?$/i.exec(css);
if (!match) {
throw new Error("invalid CSS code: " + css);
}
let vals = match[1];
if (vals.length === 3) {
vals = vals[0] + vals[0] + vals[1] + vals[1] + vals[2] + vals[2];
}
return new this(
parseInt(vals.substring(0, 2), 16),
parseInt(vals.substring(2, 4), 16),
parseInt(vals.substring(4, 6), 16)
);
}
}
static
키워드가 붙은 메서드는 개별 인스턴스 메서드가 아닌Color
클래스 자체의 메서드가 된다.
Color.fromCSS = function fromCSS(css) {};
- ES5 식으로는 위와 같이 표현된다. 프로토타입 속성이 아님에 유의하자.
접근자 속성 코드 살펴보기
class Color {
constructor(r = 0, g = 0, b = 0) {
this.r = r;
this.g = g;
this.b = b;
}
get rgb() {
return `rgb(${this.r}, ${this.g}, ${this.b})`;
}
set rgb(value) {
let s = String(value);
let match = /^rgb\((\d{1, 3}),(\d{1, 3}), (\d{1,3})\)$/i.exec(
s.replace(/\s/g, "")
);
if (!match) {
throw new Error(`Invalid rgb color string '${s}'`);
}
}
toString() {
return this.rgb;
}
static fromCSS(css) {
const match = /^#?([0-9a-f]{3}|[0-9a-f]{6});?$/i.exec(css);
if (!match) {
throw new Error("invalid CSS code: " + css);
}
let vals = match[1];
if (vals.length === 3) {
vals = vals[0] + vals[0] + vals[1] + vals[1] + vals[2] + vals[2];
}
return new this(
parseInt(vals.substring(0, 2), 16),
parseInt(vals.substring(2, 4), 16),
parseInt(vals.substring(4, 6), 16)
);
}
}
let c = new Color();
r.rgb = "rgb(30, 144, 255)";
ES5 에서 접근자 코드를 작성했던 방법
ES5 에서는 아래와 같이 작성해야 했다.
Object.defineProperty(Color.prototype, "rgb", {
get: function () {
return `${this.r}, ${this.g}, ${this.b}`;
},
set: function (value) {
// ...
},
configurable: true,
});
static 접근자
원한다면 정적인 접근자 속성 정의도 가능하다.
class StaticAccessorExample {
static get cappedClassName() {
return this.name.toUpperCase();
}
}
계산된 메서드 이름
런타임에 결정되는 이름으로 메서드를 만들고 싶을 때 유용하다.
let name = "foo" + Math.floor(Math.random() * 1000);
class SomeClass {
[name]() {
// ...
}
}
- 대괄호 안에 어떤 표현이든 넣을 수 있다.
- 클래스 정의가 평가되는 시점에 식이 평가된다.
- 결과가 문자열이나 심볼이 아닌 경우, 문자열로 반환된다.
- 결과가 메서드 이름으로 사용된다.
정적 메서드
class Guide {
static [6 * 7]() {
// Guide["42"]() -> logging "GOOD"
console.log("GOOD!");
}
}
ES5
var name = "foo" + Math.floor(Math.random() * 1000);
SomeClass.prototype[name] = function () {
// ...
};
반응형
'자바스크립트 > 모던 자바스크립트' 카테고리의 다른 글
모던 자바스크립트, 디스트럭처링 (Desctructuring) (0) | 2023.02.08 |
---|---|
자바스크립트 클래스 3 - 상속 (0) | 2023.02.01 |
자바스크립트 클래스 1 - 기본 개념 (0) | 2023.02.01 |
ES6 이후에 새롭게 정의된 Object 편의 정적 메서드들 (0) | 2023.01.30 |
모던 자바스크립트, 메서드 정의 문법과 super, [[HomeObject]] (0) | 2023.01.25 |