javascript.info, https://ko.javascript.info/static-properties-methods
참고 사이트에 내용을 개인적으로 복습하기 편하도록 재구성한 글입니다.
자세한 설명은 참고 사이트를 살펴보시기 바랍니다.
"prototype"
이 아닌 클래스 함수 자체에 메서드를 설정할 수도 있습니다. 이런 메서드를 정적(static) 메서드라고 부릅니다.
정적 메서드는 아래와 같이 클래스 안에서 static
키워드를 붙여 만들 수 있습니다.
class User {
static staticMethod() {
alert(this === User);
}
}
User.staticMethod(); // true
정적 메서드는 메서드를 프로퍼티 형태로 직접 할당하는 것과 동일한 일을 합니다.
class User { }
User.staticMethod = function() {
alert(this === User);
};
User.staticMethod(); // true
User.staticMethod()
가 호출될 때 this
의 값은 클래스 생성자인 User
자체가 됩니다(점 앞 객체).
정적 메서드는 어떤 특정한 객체가 아닌 클래스에 속한 함수를 구현하고자 할 때 주로 사용됩니다.
객체 Article
이 여러 개 있고 이들을 비교해줄 함수가 필요하다고 가정해 봅시다. 가장 먼저 아래와 같이 Article.compare
를 추가하는 방법이 떠오를 겁니다.
class Article {
constructor(title, date) {
this.title = title;
this.date = date;
}
static compare(articleA, articleB) {
return articleA.date - articleB.date;
}
}
// 사용법
let articles = [
new Article("HTML", new Date(2019, 1, 1)),
new Article("CSS", new Date(2019, 0, 1)),
new Article("JavaScript", new Date(2019, 11, 1))
];
articles.sort(Article.compare);
alert( articles[0].title ); // CSS
여기서 Article.compare
는 article(글)을 비교해주는 수단으로, 글 전체를 "위에서" 바라보며 비교를 수행합니다. Article.compare
이 글 하나의 메서드가 아닌 클래스의 메서드여야 하는 이유가 여기에 있습니다.
이번에 살펴볼 예시는 "팩토리" 메서드를 구현한 코드입니다. 다양한 방법을 사용해 조건에 맞는 article
인스턴스를 만들어야 한다고 가정해 봅시다.
📌 매개변수(title
, date
등)를 이용해 관련 정보가 담긴 article 생성
📌 오늘 날짜를 기반으로 비어있는 article 생성
📌 기타 등등
첫 번째 방법은 생성자를 사용해 구현할 수 있습니다. 두 번째 방법은 클래스에 정적 메서드를 만들어 구현할 수 있습니다.
아래 Article.createTodays()
같이 말이죠.
class Article {
constructor(title, date) {
this.title = title;
this.date = date;
}
static createTodays() {
// this는 Article입니다.
return new this("Today's digest", new Date());
}
}
let article = Article.createTodays();
alert( article.title ); // Today"s digest
이제 Today's digest라는 글이 필요할 때마다 Article.createTodays()
를 호출하면 됩니다. 여기서도 마찬가지로 Article.createTodays()
는 article의 메서드가 아닌 전체 클래스의 메서드입니다.
정적 메서드는 아래 예시와 같이 항목 검색, 저장, 삭제 등을 수행해주는 데이터베이스 관련 클래스에도 사용됩니다.
// Article은 article을 관리해주는 특별 클래스라고 가정합시다.
// article 삭제에 쓰이는 정적 메서드
Article.remove({id: 12345});
정적 프로퍼티는 일반 클래스 프로퍼티와 유사하게 생겼는데 앞에 static
이 붙는다는 점만 다릅니다.
class Article {
static publisher = "Ilya Kantor";
}
alert( Article.publisher ); // Ilya Kantor
위 예시는 Article
에 프로퍼티를 직접 할당한 것과 동일하게 동작합니다.
Article.publisher = "Ilya Kantor";
정적 프로퍼티와 메서드는 상속됩니다.
아래 예시에서 Animal.compare
와 Animal.planet
은 상속되어서 각각 Rabbit.compare
와 Rabbit.planet
에서 접근할 수 있습니다.
class Animal {
static planet = "지구";
constructor(name, speed) {
this.speed = speed;
this.name = name;
}
run(speed = 0) {
this.speed += speed;
alert(`${this.name}가 속도 ${this.speed}로 달립니다.`);
}
static compare(animalA, animalB) {
return animalA.speed - animalB.speed;
}
}
// Animal을 상속받음
class Rabbit extends Animal {
hide() {
alert(`${this.name}가 숨었습니다!`);
}
}
let rabbits = [
new Rabbit("흰 토끼", 10),
new Rabbit("검은 토끼", 5)
];
rabbits.sort(Rabbit.compare);
rabbits[0].run(); // 검은 토끼가 속도 5로 달립니다.
alert(Rabbit.planet); // 지구
이제 Rabbit.compare
을 호출하면 Animal.compare
가 호출됩니다.
이게 가능한 이유는 프로토타입 때문입니다. 이미 예상하셨겠지만, extends
키워드는 Rabbit
의 [[Prototype]]
이 Animal
을 참조하도록 해줍니다.
따라서 Rabbit extends Animal
은 두 개의 [[Prototype]]
참조를 만들어 냅니다.
함수 Rabbit
은 프로토타입을 통해 함수 Animal
을 상속받습니다.
Rabbit.prototype
은 프로토타입을 통해 Animal.prototype
을 상속받습니다.
이런 과정이 있기 때문에 일반 메서드 상속과 정적 메서드 상속이 가능합니다.
class Animal {}
class Rabbit extends Animal {}
// 정적 메서드
alert(Rabbit.__proto__ === Animal); // true
// 일반 메서드
alert(Rabbit.prototype.__proto__ === Animal.prototype); // true