JavaScript/함수형 프로그래밍

[JavaScript]함수형 프로그래밍 - 불변성(immutable)

DevStory 2021. 7. 18.

함수형 프로그래밍의 핵심 개념 중 하나인 불변성에 대해 설명을 합니다.


불변성(immutable)

이력서에서 본인의 사진을 숨기는 작업을 진행할 경우 싶은 경우 가능한 방법은 두 가지입니다.

(더 창의적이고 다양한 방법이 있겠지만 2가지라고 가정합시다.)

첫 번째 방법은 원본 이력서에서 사진을 빗금 처리하던지 사진을 가립니다.

두 번째 방법은 원본 이력서의 복사본을 만들어 복사본을 수정하는 방법입니다.

 

두 가지 방법 중에서 사진을 숨기는 작업을 취소해야 하는 경우가 있을 수도 있으므로 안전한 방법은 두 번째 방법입니다.


JavaScript와 불변성

자바스크립트에서 데이터가 변경되었을 경우 변하는지 불변하는지 예제 코드를 통해 알아보도록 합니다.

 

예제코드

 

변수

변수의 경우에는 원본 변수인 myAge의 값이 변경이 되지 않습니다. 불변성을 지켰다고 할 수 있습니다.

var myAge = 29;

function setMyAge(myAgeParam, age) {
  myAgeParam = age;
  return myAgeParam;
}

console.log(`함수 호출 전 : ${myAge}`);
console.log(`함수 반환 값 : ${setMyAge(myAge, 30)}`);
console.log(`함수 호출 후 : ${myAge}`);

 

객체

setAgeOrigin 함수는 전달받은 user의 age를 변경합니다.

var userInfoOrigin = {
  name: "JaeSeong",
  age: 29
};

function setAgeOrigin(user, age) {
  user.age = age;
  return user;
}

console.log(`함수 호출 전 : ${userInfoOrigin.age}`);
console.log(`함수 반환 값 : ${setAgeOrigin(userInfoOrigin, 30).age}`);
console.log(`함수 호출 후 : ${userInfoOrigin.age}`);

원본 객체인 userInfoOrigin의 age도 변경이 되었습니다. 자바스크립트에서 Array와 Object는 참조 주소를 공유하는 얕은 복사(Shallow Copy)로 인해 원본 데이터도 변경이 됩니다.

(이력서의 복사본을 수정하였는데, 원본도 수정되는 아이러니한 상황이 발생합니다.)

 

얕은 복사와 깊은 복사에 대해서는 포스팅한 글이 있으므로 읽고 오시면 불변성을 이해하는데 도움이 됩니다.

얕은 복사와 깊은 복사 알아보기


Object.assign()을 사용

Object.assign()는 원본 데이터의 불변성을 100% 지켜주지 않습니다.

/**
 * Example 3
 */
var userInfoObject = {
  name: "JaeSeong",
  info: {
    age: 29
  }
};

/**
 * 1 Level Change
 */
function setAgeLevelOne(user, name) {
  var returnValue = Object.assign({}, user, { name: name });
  return returnValue;
}

/**
 * 2 Level Change
 */
function setAgeLevelTwo(user, age) {
  var returnValue = Object.assign({}, user);
  returnValue.info.age = age;
  return returnValue;
}

console.log(`*****Example 3 One Level*****`);
console.log(`함수 호출 전 : ${userInfoObject.name}`);
console.log(`함수 반환 값 : ${setAgeLevelOne(userInfoObject, "Immutable").name}`);
console.log(`함수 호출 후 : ${userInfoObject.name}`);

console.log(`*****Example 3 Two Level*****`);
console.log(`함수 호출 전 : ${userInfoObject.info.age}`);
console.log(`함수 반환 값 : ${setAgeLevelTwo(userInfoObject, 30).info.age}`);
console.log(`함수 호출 후 : ${userInfoObject.info.age}`);

setAgeLevelOne 함수는 userInfoObject 객체의 1레벨 속성인 name을 변경합니다.

함수 호출 후 원본 데이터는 변경되지 않았습니다.

 

하지만, userInfoObject 객체의 2레벨 속성인 age를 변경하는 setAgeLevelTwo 함수를 호출 후 원본 데이터도 변경되었음을 확인할 수 있습니다.

 

Object.assign()은 1레벨까지는 깊은 복사가 되지만, 2 레벨 부터는 깊은 복사가 되지 않으므로 원본 데이터의 불변성을 지켜주지 않습니다.

즉, Object.assign()은 불변성 함수가 아닙니다.


화살표 함수와 스프레드 연산자를 활용

스프레드 연산자를 사용하여 원본 객체를 새로운 객체에 복사한 다음 객체의 속성을 변경합니다.

주의사항으로 화살표 함수에서 중괄호 {}를 사용해 객체를 반환할 수 없으므로 괄호 ()가 필요합니다.

var userInfoEx4 = {
  name: "JaeSeong",
  info: {
    address: "Busan",
    age: 29
  }
};

var setAgeArrow = (user, age) => ({
  ...user,
  info: {
    ...user.info,
    age
  }
});

console.log(`함수 호출 전 : ${userInfoEx4.info.age}`);
console.log(setAgeArrow(userInfoEx4, 30));
console.log(`함수 반환 값 : ${setAgeArrow(userInfoEx4, 30).info.age}`);
console.log(`함수 호출 후 : ${userInfoEx4.info.age}`);

스프레드 연산자와 화살표 함수를 사용하면, 객체도 불변성을 지킬 수 있습니다.


요약

1. 변수는 불변성을 보장한다.

2. 객체와 배열은 불변성을 보장하지 않는다.

3. 스프레드 연산자화살표 함수를 사용하면 객체와 배열도 불변성을 지킬 수 있다.

반응형

댓글