정적 메서드와 정적 프로퍼티

김윤진·2022년 3월 25일
0

JavaScript

목록 보기
5/10

reference
https://ko.javascript.info/static-properties-methods

prototype이 아닌 클래스 함수 자체에 메서드를 설정할 수 있다
이런 메서드를 정적(static) 메서드라고 부른다

class Person {
 	static staticMethod() {
     	console.log("static"); 
    }
}

Person.staticMethod(); // static

정적 메서드는 메서드를 프로퍼티 형태로 직접 할당하는 것과 동일한 일을 한다

class Person { }

Person.staticMethod = function() {
 	console.log("static"); 
}

Person.staticMethod(); // static

Person.staticMethod()가 호출될 때 this의 값은 클래스 생성자인 User 자체가 된다 (점 앞 객체)

정적 메서드는 어떤 특정한 객체가 아닌 클래스에 속한 함수를 구현할 때 주로 사용된다


class Posting {
 	constructor(title, date) {
      	this.title = title;
      	this.date = date;
    }
  
  	static compareDate(postingA, postingB) {
     	return postingA.date - postingB.date; 
    }
}

let postings = [
 	new Posting("정적 메서드", new Date(2022, 12, 22)),
    new Posting("은닉화", new Date(2022, 11, 28)),
    new Posting("객체지향", new Date(2022, 05, 10)),
];

posting.sort(Posting.compareDate);

conole.log(postins[0].title); // 객체지향

Posting.compareDate는 posting을 비교해주는 수단으로 글 전체를 위에서 바로보며 비교를 수행한다
Posting.compareDate는 글 하나의 메서드가 아닌 클래스의 메서드여야 하는 이유이다


팩토리 메서드를 구현한 코드이다

class Posting {
	constructor(title, date) {
     	this.title = title;
      	this.date = date;
    }
  
  	static createToday() {
      	// this는 Posting이다
    	return new this("Monday", new Date());
    }
}

let posting = Posting.createToday();
console.log(posting.title); // Monday

이제 Monday라는 문자가 필요할 때마다 Posting.createToday()를 호출하면 된다
여기서도 마찬가지로 Posting.createToday()는 posting 메서드가 아닌 전체 클래스의 메서드이다


정적 메서드는 항목 검색, 저장, 삭제, 수정 등 데이터 베이스 관련 클래스에서도 사용할 수 있다

Posting.remove({ id: 1001 })

정적 프로퍼티

정적 프로퍼티도 일반 클래스 프로퍼티와 유사하게 앞에 static이 붙는다

class Posting {
 	static postA = "함수형 프로그래밍"; 
}

console.log(Posting.postA); // 함수형 프로그래밍

Posting에 프로퍼티를 직접 할당하는 것과 동일하게 동작한다

Posting.postA = "함수형 프로그래밍";

정적 프로퍼티와 메서드 생속

정적 프로퍼티와 메서드는 상속이된다

class Human {
 	static korean = "한국인";

	constructor(name, speed) {
      	this.name = name;
      	this.speed = speed;
    }

	run(speed = 0) {
     	this.speed += speed;
      	console.log(`${this.name}${this.speed}속도로 달린다`);
    }

	static compare(humanA, humanB) {
    	return humanA.speed - humanB.speed;
    }
}

class SoccerPlayer extends Human {
 	goal() {
     	console.log(`${this.name}이 골을 넣었습니다!`);
    }
}

let soccerPlayer = [
	new SoccerPlayer("손흥민", 30);
  	new SoccerPlayer("케인", 25);
];

soccerPlayer.sort(SoccerPlayer.compare);

soccerPlayer[0].run(); // 케인이 25속도로 달린다

console.log(SoccerPlayer.korean); // 한국인

SoccerPlayer.compare를 호출하면 Human.compare가 호출된다
이게 가능한 이유는 extend키워드는 SoccerPlayer[[Prototype]]Human을 참조하게 해준다

따라서 SoccerPlay extends Human은 두개의 [[Prototype]] 참조를 만들어낸다

  • 함수 SoccerPlayer는 포로토타입을 통해 함수 Human을 상속받는다
  • SoccerPlayer.prototype은 프로토타입을 통해 Human.prototype을 상속받는다

이런 과정이 있기 때문에 일반 메서드 상속과 정적 메서드 상속이 가능하다

class Human {}
class SoccerPlayer extends Human {}

// 정적 메서드
console.log(SoccerPlayer.__proto__ === Human); // true

// 일반 메서드
console.log(SoccerPlayer.__proto__ === Human.prototype); // true

정리

정적 메서드는 특정 클래스 인스턴스가 아닌 클래스 전체에 필요한 기능을 만들 때 사용할 수 있다

인스턴스끼리 비교해주는 메서드 Posting.compareDate(postingA, postingB)이나 팩토리 메서드 Posting.createToday()를 만들 때 정적 메서드가 쓰인다

정적 메서드는 클래스 선언부 안에 위차하고 앞에 static이라는 키워드가 붙는다

정적 프로퍼티는 데이터를 클래스 수준에 저장하고 싶을 때 사용한다
정적 프로퍼티 역시 개별 인스턴에 묶이지 않는다

class Class {
 	static property = "property";

	static method() {
    }
}
// 위와 같다
Class.property = "property"'
Class.method = function() { }

정적 프로퍼티와 정적 메서드는 상속이 가능하다
class B extends A는 클래스 B의 프로토타입이 클래스 A를 가리키게 한다 (B.[[Prototype]] = A)
따라서 B가 원하는 프로퍼티나 메서드를 찾지 못하면 A로 검색이 이어진다


Object를 상속받는 클래스

객체는 보통 Object.prototype을 상솓받고 hasOwnProperty같은 일반 객체 메서드에 접근할 수 있다

class Human {
 	consturctor(name) {
     	this.name = name; 
    }
}

let human = new Human("Son");

// 메서드 hasOwnPropertysms Object.protoype에서 왔다
console.log(human.hasOwnProperty("name")); // true

만약 Object를 상속받는다면?

class Human extends Object {
 	consturctor(name) {
     	this.name = name; 
    }
}

let human = new Human("Son");

console.log(human.hasOwnProperty("name")); // Error

에러를 해결해보면

상속받는 클래스는 생성자 super()를 반드시 호출해야 한다
그렇지 않으면 this가 정의되지 않는다

class Human extends Object {
 	consturctor(name) {
      	super();
     	this.name = name; 
    }
}

let human = new Human("Son");

console.log(human.hasOwnProperty("name")); // true

아직 class Human extends Objectclass Human은 다른점이 있다

extends문법은 두개의 프로토타입을 설정한다

  1. 생성자 함수의 prorotype 사이 (일반 메서드용)
  1. 생성자 함수 자체 사이 (정적 메서드용)

class Human extends Object는 다음과 같은 관계를 만든다

class Human extends Object {}
console.log(Human.prototype.__proto__ === Object.prototype) // true
console.log(Human.__proto__ === Object); // true

따라서 HumanObject의 정적 메서드에 접근할 수 있다

class Human extends Object {}

// 보통은 Object.getOwnPrototypeNames 로 호출한다
console.log(Human.getOwnPrototypeNames({a: 1, b: 2})); // a, b

그러나 extends Object가 없으면 Human.__proto__Object로 설정되지 않는다

class Human {}

console.log(Human.prototype.__proto__ === Object.prototype) // true
console.log(Human.__proto__ === Object); // false
console.log(Human.__proto__ === Function.prototype) // true (모든 함수의 기본 프로토타입)

console.log(Human.getOwnPrototypeNames({ a: 1, b: 2 })); // Error

이런 이유로 Human에서 Object의 정적 메서드를 사용할 수 없다

한편 Function.prototypecall, apply, bind등 일반 함수 메서드를 가진다
내장 객체, Object의 생성자는 Object.__proto === Function.prototype 관계를 갖기 때문에 Function.prototype에 정의된 함수 메서드는 두 경우 모두 사용할 수 있다

0개의 댓글