→ 객체 지향은 데이터와 데이터 관계의 본질에 초점을 맞춥니다.
자바스크립트는 두 특징을 모두 갖고 있습니다.
이러한 특징을 가진 두 패러다임을 적절히 잘 결합하면 최고의 코드를 생산할 수 있습니다.
함수형 | 객체지향형 | |
---|---|---|
합성 단위 | 함수 | 객체(class) |
프로그래밍 스타일 | 선언적 | 명령형 |
데이터와 기능 | 독립적인 순수함수가 느슨하게 결합 | 클래스 안에서 메서드와 단단하게 결합 |
상태 관리 | 객체를 불변 값으로 취급 | 인스턴스 메서드를 통해 객체를 변이시킴 |
제어 흐름 | 함수와 재귀 | 루프와 조건 분기 |
스레드 안전 | 동시성 프로그래밍 가능 | 캡슐화하기 어려움 |
캡슐화 | 모든 것이 불변이라 필요없음 | 데이터의 무결성 때문에 필요 |
동시성 프로그래밍 : Concurrent : 시분할로 여러 작업이 마치 동시에 일어나는 것처럼 보이게 하는것
먼저 자바스크립트에서는 원시값 (String, Number, Symbol, Boolean, BigInt, undefined, null)을 const
선언을 사용해서 정의를 하면 선언된 변수는 더 이상 변하지 않으므로 해당 변수에 대한 불변성을 지킬 수 있습니다.
하지만 자바스크립트에서 거의 대부분의 객체는Object
의 인스턴스 입니다. 즉, 불변성을 지키기 어렵습니다.
이를 위해서 객체를 값으로 취급하는 방식을 소개합니다.
const userInfo = (name, age) => {
const _name = name
const _age = age || 0
return {
name: () => {
return _name
},
age: () => {
return _age
},
modifyInfo: (newName, newAge) => {
return userInfo(newName, newAge)
}
}
}
const DoodreamInfo = userInfo('Luke', 29)
DoodreamInfo.age() // 29
const newDoodreamInfo = DoodreamInfo.modifyInfo('Doo', 30)
newDoodreamInfo.age() // 30
위 패턴에서은 const
선언으로 정의한 DoodreamInfo 라는 객체값의 프로퍼티에 직접 값을 넣지 않음으로서 객체 내부의 값을 직접 접근 시키지 않습니다. age와 name과 같은 함수 프로퍼티를 사용함으로서 getter와 같은 역할을 하게됩니다.
이렇게 정의된 인스턴스는 값을 정의한 후로 내부에 정의된 데이터가 변하지 않습니다. 즉, 외부에서 객체내부의 값을 직접 수정하지 못함으로서 객체 불변성을 지키게됩니다. 이러한 패턴을 사용하는 데이터는
tuple, pair, point, zipCode, coordinate, money, date
같은 형식으로 만들어지는 형식이 모두 값 객체 패턴입니다.
이런식의 패턴은 기존 값을 변하게 않게 하기 위해서 레거시 객체와 상호작용하거나, 계층적 데이터 구조에서 사용되게 됩니다.
const freezeObj = Object.freeze({data: 'text', data2: 'text2'})
freezeObj.data = 2
freezeObj.data // 'text'
Object.freeze
라는 함수는 객체의 한 단계의 프로퍼티들의 값들을 동결합니다. Object 안의 메타속성(숨김 속성)인 writable
속성을 false로 설정하여 프로퍼티 값이 바꾸니는 것을 방지합니다. 하지만 명확하게 프로퍼티에 객체가 있는 중첩 객체 데이터들은 동결하지 못합니다.
이러한 동결을 얕은 동결(shallow freeze)
이라고 표현합니다.
확실하게 모든 데이터들을 동결하고 싶다면 재귀적으로 밑의 모든 객체에 대하여 freeze 적용을 해주어야 한다.
// MDN 출처
function deepFreeze(object) {
// 객체에 정의된 속성명을 추출
const propNames = Object.getOwnPropertyNames(object);
// 스스로를 동결하기 전에 속성을 동결
for (let name of propNames) {
let value = object[name];
object[name] = value && typeof value === "object" ? deepFreeze(value) : value;
}
return Object.freeze(object);
}
애플리케이션에서 하나의 객체의 값을 절대 변경시키지 않고 데이터의 흐름을 이어가는 것은 상당히 불편합니다.
그때 그때 원본객체의 값을 이용해서 새로운 객체를 생성하여 엄격하게 한 객체에 대한 불변성을 지키며 대응한다면 큰 도움이 될 것 입니다.