안녕하세요.
이 공간은 제가 프론트엔드를 처음 접하며 배운 것을 주저리주저리 쓰는 공간입니다.
이번 내용은 javascript 14편입니다.

getter와 setter

저번에 살펴본 private 속성을 사용하면 외부에서는 #length 속성에 접근이 불가능했어요.
square 객체의 length 속성 확인도, 속성 변경도 불가능했습니다.
그래서 등장한 개념이 getter와 setter입니다.

class Square {
  #length

  constructor(length) {
    this.setLength(length)
  }

  // 함수를 사용해서 내부에서 예외처리를 해줍니다.
  setLength(length) {
    if (length <= 0) {
      throw "길이는 0보다 커야합니다!"
    }
    this.#length = length
  }

  getLength(value) {
    return this.#length
  }

  getPerimeter() { return 4 * this.#length }
  getArea() { return this.#length * this.#length }
}

// 클래스를 사용합니다.
const square = new Square(20)
console.log(`한 변의 길이는 ${square.getLength()}입니다.`)

// 예외를 발생시켜볼게요.
square.setLength(-10)

이처럼,
get()메소드처럼 속성 값을 확인할 때 사용하는 메소드를 getter,
set()메소드처럼 속성 값을 변경할 때 사용하는 메소드를 setter

라고 합니다.

만약 사용자가 값을 읽고(get) 변경하는 것(set)을 거부하고 싶다면, getter와 setter는 사용하지 않아도 됩니다.

이 getter와 setter의 사용량이 많아지며, 아래와 같은 문법을 제공하기 시작합니다.

class 클래스 이름 {
  get 이름 () { return 값 }
  set 이름 (value) { }
}

얼핏 보면 예시에서 봤던 get(), set()가 더 쉬워보일 수 있지만,
위 문법을 사용하면 코드가 훨씬 간단해지는 이점이 있습니다.

class Square {
  #length

  // this에 length값을 지정하면 set length(length) 메소드 부분이 호출됩니다.
  constructor(length) {
    this.length = length
  }

  // 모든 get과 set 뒤에 띄어쓰기를 넣어줍니다.
  get length() { 
    return this.#length 
  }

  get perimeter() {
    return this.#length * 4
  }

  get area() {
    return this.#length * this.#length
  }

  set length(length) {
    if (length <= 0) {
      throw "길이는 0보다 커야합니다!"
    }
    this.#length = length
  }
}

// 클래스를 사용합니다.
const squareA = new Square(20)
console.log(`한 변의 길이: ${squareA.length}`)
console.log(`둘레: ${squareA.perimeter}`)
console.log(`넓이: ${squareA.area}`)

// 생성자 함수로 예외를 발생시킵니다.
const squareB = new Square(-20)


이렇게 속성을 활용하는 형태처럼 보다 쉽게 getter와 setter를 사용할 수 있게 됩니다.

static

자바스크립트에는 원래 클래스라는 기능이 없었습니다.
하지만 위 getter와 setter처럼 다양한 패턴을 고안하고, 그러한 패턴들을 활용하기 위해 클래스 문법들이 계속 추가된 것이라고 할 수 있어요.
static 속성과 메소드도 그 중 하나입니다.
statci 속성과 메소드를 우리말로 정적 속성, 정적 메소드
라고 부르기도 해요.

class 클래스 이름 {
  static 속성 = 값
  static 메소드() {
    내용
  }
}

이 정적속성과 정적메소드의 가장 큰 특징은
인스턴스를 만들지 않고 사용할 수 있다는 점입니다.

이 말은 호출 방법도 프로토타입 메소드와는 다르다는 의미인데요.
프로토타입 메소드는 인스턴스로 호출하는 반면,
정적 메소드는 클래스로 호출합니다!
클래스 이름 뒤에 점을 찍고, 속성과 메소드를 사용하면 됩니다.

클래스 이름.속성
클래스 이름.메소드()

정적 메소드는 아래 예시처럼 사용이 가능합니다.

class Square {
  // private 속성과 static 속성은 동시 적용도 가능합니다!
  #length
  static #counter = 0
  static get counter() { 
    return Square.#counter
  }

  constructor(length) {
    this.length = length
    Square.#counter += 1
  }

  static perimeterOf(length) {
    return length * 4
  }

  static areaOf(length) {
    return length * length
  }

  get length() { return this.#length }
  get perimeter() { return this.#length * 4 }
  get area() { return this.#length * this.#length }

  set length(length) {
    if (length <= 0) {
      throw "길이는 0보다 커야합니다!"
    }
    this.#length = length
  }
}

const squareA = new Square(10)
const squareB = new Square(20)
console.log(`총 생성된 Square 인스턴스: ${Square.counter}개`)
console.log(`한 변의 길이가 10인 정사각형의 둘레: ${Square.perimeterOf(10)}`)
console.log(`한 변의 길이가 20인 정사각형의 둘레: ${Square.perimeterOf(20)}`)
console.log(`한 변의 길이가 10인 정사각형의 넓이: ${Square.areaOf(10)}`)
console.log(`한 변의 길이가 20인 정사각형의 넓이: ${Square.areaOf(20)}`)

오버라이드

부모가 갖고 있는 함수를 자식에게 다시 선언해 덮어쓰는 것을 말합니다.

// 클래스를 선언합니다.
class eMart {
  call () {
    this.incheon()
    this.seoul()
    this.jeju()
  }

  incheon() { console.log('이마트 인천점 호출')}
  seoul() { console.log('이마트 서울점 호출')}
  jeju() { console.log('이마트 제주점 호출')}
}

// 인스턴스를 생성합니다.
new eMart().call()

주말에 이마트를 꼭! 반드시! 가야하기 때문에 까먹지 않으려고 저는 이마트를 썼습니다.
위 코드에서 eMart 클래스를 상속받는 다른 클래스를 선언해보겠습니다.

// 클래스를 선언합니다.
class eMart {
  call () {
    this.incheon()
    this.seoul()
    this.jeju()
  }

  incheon() { console.log('이마트 인천점 호출')}
  seoul() { console.log('이마트 서울점 호출')}
  jeju() { console.log('이마트 제주점 호출')}
}

// 오버라이드 합니다.
class eMart24 extends eMart {
  incheon() { console.log('이마트24 인천점 호출') }
}

// 인스턴스를 생성합니다.
new eMart24().call()


이마트 인천점이 갑자기 이마트24 인천점으로 바뀌었네요?

이로 통해 볼 수 있는 점은

call() 메소드에서 동일한 incheon() 메소드를 실행했지만,
incheon() 메소드가 덮어씌워지면서 새로운 incheon()메소드의 내용이 출력된다는 점입니다.

만약 부모에 있던 메소드의 내용도 같이 사용하고 싶다면,
super.메소드() 형태를 사용해야 합니다.
인천짱짱맨

// 클래스를 선언합니다.
class eMart {
  call () {
    this.incheon()
    this.seoul()
    this.jeju()
  }

  incheon() { console.log('이마트 인천점 호출')}
  seoul() { console.log('이마트 서울점 호출')}
  jeju() { console.log('이마트 제주점 호출')}
}

// 오버라이드 합니다.
class eMart24 extends eMart {
  incheon() { 
    super.incheon() // super 메소드를 사용해줬어요.
    console.log('이마트24 인천점 호출') }
}

// 인스턴스를 생성합니다.
new eMart24().call()

profile
수제 에러코드 전문점 / 불량코드 원조 맛집

0개의 댓글