프론트엔드/JavaScript

[JavaScript] 클린 코드 - 4. 객체와 자료구조

1. getter와 setter를 사용한다.

JavaScript는 public, private 키워드나 인터페이스 문법이 존재하지 않는다.

(TypeScript에선 모두 제공하고 있다. 굿굿)

그래서 중요한 내용을 내부 인터페이스로 따로 분리하여 관리하는 것이 어렵다.

대신 getter와 setter를 사용하는 것을 추천한다. 다음과 같은 장점을 가질 수 있다.

  • 단순히 속성을 얻는 것 이상의 행동을 쉽게 구현할 수 있다.
  • 만약 검증 로직이 필요하다면 간단하게 추가할 수 있다.
  • 내부용 API를 캡슐화 시킬 수 있다.
  • getting, setting 로그를 관리하거나 에러 처리를 쉽게 할 수 있다.
  • 서버에서 객체 속성을 받아올 때 lazy load 할 수 있다.
    • lazy load - 페이지를 읽는 시점에서 중요하지 않은 리소스를 추후에 불러오는 것
// BAD
function makeBankAccount() {
  // ...

  return {
    // ...
    balance: 0,
  };
}

const account = makeBankAccount();
account.balance = 100;

// GOOD!
function makeBankAccount() {
  // private으로 선언된 변수
  let balance = 0;

  // return을 통해 public으로 선언된 "getter"
  function getBalance() {
    return balance;
  }

  // return을 통해 public으로 선언된 "setter"
  function setBalance(amount) {
    // ... balance를 업데이트하기 전 검증로직
    balance = amount;
  }

  return {
    // ...
    getBalance,
    setBalance,
  };
}

const account = makeBankAccount();
account.setBalance(100);

 

2. 객체에 비공개 멤버를 만든다.

JavaScript의 클로저 개념을 이용하는 방법이다.

_name 변수를 외부에서 접근 못하게 만들어 일종의 private 기능을 할 수 있다.

// BAD - 외부에서 _name 변수에 직접 접근할 수 있다.
function Hello(name) {
  this._name = name;
}

Hello.prototype.say = function () {
  console.log("Hello, " + this._name);
};

const hello1 = new Hello("Lee");
const hello2 = new Hello("Son");
const hello3 = new Hello("Kim");

hello1.say(); // 'Hello, Lee'
hello2.say(); // 'Hello, Son'
hello3.say(); // 'Hello, Kim'
hello1._name = "anonymous";
hello1.say(); // 'Hello, anonymous'

// GOOD! - 외부에서 _name에 접근할 방법이 전혀 없게 됐다.
function hello(name) {
  const _name = name;
  return function () {
    console.log("Person, " + _name);
  };
}

const hello1 = hello("Lee");
const hello2 = hello("Son");
const hello3 = hello("Kim");

hello1(); // 'Hello, Lee'
hello2(); // 'Hello, Son'
hello3(); // 'Hello, Kim'

 

참조