배열에 이어 오늘은 객체를 안전하고 깔끔하게 다루는 방법에 대해 알아보자.
간략하게 표현할 수 있도록 나온 최신 문법들을 익혀두면 좀 더 편리하게 객체를 생성 및 조작할 수 있다.
Shorthand Property & Method Name
객체에서 key와 value명이 같은 경우 축약해서 사용할 수 있게 만들어주는 문법이다.const name = "영희"; const age = 20; const gender = "female"; const info = { name:name, age:age, gender:gender }; //shorthand Property names 적용 코드 const info = { name, age, gender }; console.log(info) //{name: '영희', age: 20, gender: 'female'}
const obj = { func: function(param) {}, }; //shorthand method names 적용 코드 const obj = { func(param) {}, };
Computed Property Name
객체의 key값을 표현식(변수, 함수 등)을 통해 지정하는 문법이다.let key = "name"; let obj = { [key] : "영희" } // obj = { name: "영희" }
function sum(a, b) { return a + b; } function sayHello() { return 'hello'; } let obj = { [`key${sum(3,5)}`] : `result is ${sum(3,5)}`, [sayHello()] : 'hi' } // obj = { // key8 : 'result is 8', // hello: 'hi' // }
객체도 구조 분해 할당으로 받아서 편하게 사용할 수 있다. 특히 리엑트에서 props
을 구조 분해 할당으로 받는 것을 흔히 볼 수 있다.
function SayHello({name}){
return <h1>Hello, {name}</h1>
}
객체의 구조분해 할당은 함수에 매개변수를 전달할 때에도 유용하게 쓸 수 있다. 일반적으로 매개변수를 전달하면 순서가 강제된다.
function Introduce(name, age, location){
return `My name is ${name}, I am ${age} years old and I live in ${location}.`
}
Introduce('영희', '20', 'korea')
//My name is 영희, I am 20 years old and I live in korea.
Introduce('영희', 'korea', '20')
//My name is 영희, I am korea years old and I live in 20.
그러나 객체를 활용하면 순서에 관계없이 매개변수를 전달할 수 있다.
function Introduce({name, age, location}){
return `My name is ${name}, I am ${age} years old and I live in ${location}.`
}
const person = {
name:'영희',
location:'korea',
age:'20'
}
Introduce(person)
//My name is 영희, I am 20 years old and I live in korea.
뿐만아니라 배열은 객체이므로 다음과 같이 인덱스 번호를 활용하여 객체로 구조 분해 할당 하여 데이터를 가공 및 사용할 수 있다.
const order = ['one','two','three']
//배열로 구조 분해 할당할 경우 'two' 자리를 비워두어야 함
const [one, ,three] = order
//객체로 구조 분해 할당할 경우 필요한 정보만 가져올 수 있음
const {0: first, 2: third} = order
console.log(first) // 'one'
console.log(third) // 'three'
기존에는 주로 switch
문을 사용하여 Matcher
를 만들었으나
function getUserType1(type) {
switch (type) {
case "ADMIN":
return "관리자";
case "INSTRUCTOR":
return "강사";
case "STUDENT":
return "수강생";
default:
return "해당없음";
}
}
이처럼 객체로 Matcher
를 만들면 불필요한 분기문을 줄일 수 있다.
function getUserType2(type) {
const USER_TYPE = {
ADMIN: "관리자",
INSTRUCTOR: "강사",
STUDENT: "수강생",
};
return USER_TYPE[type] ?? "해당없음";
}
// 지역변수 만들지 않고 바로 리턴 가능
function getUserType3(type) {
return (
{
ADMIN: "관리자",
INSTRUCTOR: "강사",
STUDENT: "수강생",
}[type] ?? "해당없음"
);
}
지역변수를 만들지 않고 바로 리턴도 가능하지만, 관심사 분리를 위해 Matcher
를 다른 파일에 따로 저장하고, import로 해당 Matcher
를 불러와서 사용하는 것이 가장 좋은 방법인 것 같다.
객체로 특정 상태를 관리할 때, 그 객체를 직접 변경하는 것이 아니라, 그 객체를 관리하는 별도의 함수를 만들어서 관리하는 것이 좋다.
const model = {
isLogin: false,
isValidToken:false
}
//직접 접근할 경우
function login(){
model.isLogin = true;
model.isValidToken = true;
}
function logout(){
model.isLogin = false;
model.isValidToken = false;
}
//리펙토링 verson
// 상태를 변경하는 함수를 만들고, 그 함수를 통해 상태를 변경한다.
function setLogin(bool){
model.isLogin = bool;
}
function setValidToken(bool){
model.isValidToken = bool
}
function login(){
setLogin(true);
setValidToken(true);
}
function logout(){
setLogin(false);
setValidToken(false);
}
상태 변경 함수를 생성하여 사용하면, log를 찍을 때 용이하고 훨씬 안전하게 상태를 관리할 수 있다. 무엇보다도 이렇게 상태 변경 함수를 사용하면 상태가 다음과 같이 변경될 것이라는 예측이 가능하다. 예측 가능한 코드를 작성하여, 동작을 예측할 수 있는 프로그램을 만드는 것 또한 클린 코드의 중요한 핵심이라는 것을 기억하자.
Object.freeze
는 마치 얼음땡에서 얼음!🧊 이 된 것 처럼 객체를 움직이지(변경하지) 못하게 하는 메서드이다. 이 메서드를 활용하면 객체를 누군가가 마음대로 변경하지 못하도록 막을 수 있다.
const obj = {prop : 42};
Object.freeze(obj);
obj.prop = 33;
console.log(obj.prop);// 42
obj.new = 22
console.log(obj) //{prop : 42}
단, Object.freeze
는 shallow freeze(얕은 동결)
이므로 깊은 동결을 원할 경우에는 라이브러리를 사용하거나, deepFreeze
와 같은 이름을 가지는 유틸함수를 별도로 직접 만들어서 사용하여야 한다.
shallow freeze(얕은 동결)
Object.freeze(object)
호출의 결과는 object 스스로의 직속 속성에만 적용되며, object에 대해서만 속성 추가, 제거, 재할당 연산을 방지한다. 그러나 만약 그 속성의 값이 객체라면, 그 객체는 동결되지 않으며 속성 추가, 제거, 재할당의 대상이 될 수 있다.const person = { name: "영희", age: "20", location: { country: "korea", city: "seoul" } }; Object.freeze(person); employee.name = "철수"; employee.address.city = "busan"; console.log(person.name) //"영희" console.log(person.location.city) //"busan"
다음은 Object.freeze MDN
에 나와있는 deepFreeze
함수이다. 재귀를 활용하여 깊은 동결을 구현할 수 있다.
function deepFreeze(object) {
// 객체에 정의된 속성명을 추출
let 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);
}
⊕ 타입스크립트에서는 readonly
를 활용하여 동결시킬 수 있다.
Clean Code(클린 코드)
/ 로버트 C. 마틴 / 2013.12.24.클린코드 자바스크립트
/ Poco Jang / 2023. 5.