Javascript OOP
2021. 05. 23
객체
서로 연관된 변수와 함수를 그룹핑하고 이름 붙인 것.
This
이 부분에 대해선 추후에 빠른 시일내로 따로 설명드리겠습니다. 일단은 this는 this가 속해있는 메소드가 속해 있는 객체를 가리키는 특수한 예약어 정도로 알고 계시면 되겠습니다.
var kim = {
name: 'kim',
first: 10,
second: 20,
sum: function () {
return this.first + this.second
},
}여기서 this는 kim이라는 객체를 가리키게 됩니다.
Class
ECMAScript 5 이전 버전의 JavaScript에는 클래스가 없습니다. 따라서, 클래스와 비슷하게 설계하는 방법은 생성자를 생성한 다음 생성자의 프로토 타입에 메서드를 할당하는 것입니다.
function Person(name, first, second) {
this.name = name
this.first = first
this.second = second
}
Person.prototype.sum = function () {
return this.first + this.second
}
var kim = new Person('kim', 10, 20)
var lee = new Person('lee', 20, 30)Person은 함수지만 new 키워드로 인해 **객체를 리턴하는 생성자 함수(constructor)**가 됩니다.
ECMAScript 6에서 클래스 형식은 다른 언어의 클래스와 비슷한 클래스 선언입니다.
class Person {
constructor(name, first, second) {
this.name = name
this.first = first
this.second = second
}
// 메소드의 경우, function 이라는 키워드를 작성하지 않아도 됩니다.
sum() {
return this.first + this.second
}
}
var kim = new Person('kim', 10, 20)
var lee = new Person('lee', 20, 30)상속
우리가 만약 누군가의 객체를 재사용 해야 한다면? 예를 들어 누군가의 클래스 코드를 가져왔으나 나는 특별한 하나의 기능을 추가하고 싶은데...? 라는 생각을 할 수 있습니다. 물론 코드 전체를 복사해서 새로운 기능을 추가시켜 나만의 새로운 클래스를 만들 수 있습니다만, 메모리를 더 먹는다던가 쓸데 없이 두배 이상의 코드가 생기는 문제 등 여러 불필요한 문제가 생기겠죠...? 그래서 등장한 것이 바로 상속입니다. 여기서는 현재 first와 second만을 인자로 받는데 만약 인자로 third도 받아서 계산을 하는 클래스를 만들고 싶다면? 다음과 같이 작성하시면 됩니다.
class Person {
constructor(name, first, second) {
this.name = name
this.first = first
this.second = second
}
sum() {
return this.first + this.second
}
}
class MyPerson extends Person {
constructor(name, first, second, third) {
super(name, first, second)
this.third = third
}
sum() {
return super.sum(this.first, this.second) + this.third
}
}
var kim = new Person('kim', 10, 20)
var lee = new MyPerson('lee', 20, 30, 40)extends라는 키워드를 사용해서 Person으로 확장(상속)하고, super라는 키워드를 사용해서 부모인 Person의 생성자 함수와 sum 메소드를 상속받고 사용가능합니다.
추가자료 - ES5에서의 상속
function Person(name, first, second) {
this.name = name
this.first = first
this.second = second
}
Person.prototype.sum = function () {
return this.first + this.second
}
var kim = new Person('kim', 10, 20)
var lee = Object.create(kim) // 또는 lee.__proto__ = kim;
lee.name = 'lee'
lee.first = 20
lee.second = 30
lee.third = 40
lee.sum = function () {
return lee.__proto__.sum.call(this) + lee.third
}
console.log(lee.name)
console.log(lee.sum())
console.log(kim.name)
console.log(kim.sum())call은 실행될 때마다 객체의 this 값을 바꾸는 다시 말해서 컨텍스트를 바꾼다.
bind는 함수의 this 값을 영구적으로 바꾸는 새로운 함수를 리턴한다.
접근자(Access) 프로퍼티
클래스 생성자 내에서 자체 프로퍼티를 만들어야 하지만, 클래스를 사용하면 프로토타입에 접근자(Accessor) 프로퍼티를 정의할 수 있습니다. Getter를 만들려면 키워드 get 다음에 공백 문자와 식별자를 사용합니다. Setter를 만들려면 set 키워드를 사용합니다.
class Person {
constructor(name) {
this._name = name
}
get name() {
return this._name
}
set name(value) {
this._name = value
}
get say() {
return this._word
}
set say(value) {
this._word = value
}
}
const ted = new Person('ted')
ted.name // "ted"
ted.say // undefined
ted.say = 'hello'
ted.say // 'hello'
ted._word // 'hello' <-- 직접접근(피하는게 좋음.)이러한 원리는 캡슐화의 이점인 정보 은닉이 된다. 메소드로 접근하는 것처럼 보이지 않기 때문에 외관상에도 깔끔하고 자바스크립트만의 특징이다. 그리고, 사실 상 this._name에 직접 접근할 수 있지만, 이러한 직접적인 접근은 피하는 것이 좋다.
정적 메소드(static methods)
자바스크립트의 클래스에서 prototype에 할당되지 않고 클래스 자체에 할당된 함수를 static 메소드라고 한다.
클래스 자체에 할당되었기 때문에 클래스의 인스턴스를 통해서는 호출될 수 없으며 클래스를 통해 호출해야 한다.
클래스가 가지고 있지만 클래스의 인스턴스에 바인딩되지 않은 기능을 구현하고자 할때 사용된다.
class Person {
constructor(name) {
this.name = name
Person.count()
}
static count() {
Person._counter = (Person._counter || 0) + 1
return Person._counter
}
static countPrinter() {
return Person._counter
}
}
const a = new Person('kim')
const b = new Person('lee')
console.log(Person.countPrinter()) // 2
console.log(b.countPrinter()) // error