Javascript에서 불변 배열 및 객체 작업

ES2015(ES6)에서 let, const 키워드가 도입되면서 javascript 변수의 선언 문제가 많이 해결되었습니다. let 선언에서도 발견되는 블록 범위 지정 개선 외에도 const는 변수가 한 번만 선언되고 해당 값이 나중에 수정되지 않도록 할 수 있습니다.

const userName = "Walter White";
userName = "Jesse Pinkman"; // error: Assignment to constant variable. 


Learn more about let and const differences.



궁금한 점이 있다면 코딩에 상수를 사용해야 하는 이유는 무엇입니까?

다음은 몇 가지 이유입니다.
  • 우발적인 할당이 발생하는 시나리오를 방지하여 자신을 보호합니다.
  • 코드를 더 읽기 쉽게 만듭니다.
  • 메모리를 최적화합니다.

  • 요컨대, 사용하는 것이 좋습니다 🙃.
    const 키워드는 Javascript에서 상수를 사용하기 위해 크게 개선되었지만, 여러분이 생각하는 것처럼 불변성을 위한 묘책은 아닙니다...

    프리미티브 대 비프리미티브 데이터 유형


    string 선언에서 데이터 유형으로 const를 사용하여 런타임에 오류를 발생시켰습니다. numberboolean와 같은 다른 기본 데이터 유형은 동일한 방식으로 작동합니다.

    const seasons = 5;
    seasons = 3; // error: Assignment to constant variable. 
    



    const isFinished = true;
    isFinished = false; // error: Assignment to constant variable. 
    


    그러나 이제 arrayobject와 같은 기본이 아닌 데이터 유형의 데이터를 변경해 보십시오.

    const enemies = ["Jack Welker", "Gus Fring", "Tuco"];
    enemies.push("Mike");
    console.log(enemies); // ['Jack Welker', 'Gus Fring', 'Tuco', 'Mike']
    



    const user = {name: "Walter White", profession: "Teacher"};
    user.profession = "Drug dealer";
    console.log(user); // {name: 'Walter White', profession: 'Drug dealer'}
    




    오류가 없는 이유는 무엇입니까?



    기본적으로 Javascript는 프리미티브 데이터 유형에 대한 참조와 값을 저장하기 위해 콜 스택 메모리 공간을 사용하는 반면, 비프리미티브 데이터 유형의 경우 힙이라는 별도의 메모리 공간을 사용합니다. 이 경우 호출 스택은 개체 및 배열 값이 아닌 힙 메모리 참조 ID만 메모리에 값으로 저장합니다.



    배열에 대한 요소를 추가하거나 개체 속성 값을 변경할 때 호출 스택의 참조 ID는 동일하게 유지되고 해당 값은 힙 메모리에서만 변경되며 오류가 발생하지 않습니다.

    There is an amazing post created by Ethan Nam explaining in depth the JavaScript’s Memory Model. I strongly advise you read it.



    배열 및 객체의 변경 차단



    원하는 목표를 달성하기 위해 Object.freeze() 를 사용하여 배열 및 객체에 대한 변경을 차단합시다. docs을 보여주세요.

    The Object.freeze() method freezes an object. A frozen object can no longer be changed; freezing an object prevents new properties from being added to it, existing properties from being removed, prevents changing the enumerability, configurability, or writability of existing properties, and prevents the values of existing properties from being changed. In addition, freezing an object also prevents its prototype from being changed. freeze() returns the same object that was passed in.



    const enemies = Object.freeze([
       "Jack Welker", 
       "Gus Fring", 
       "Tuco"
    ]);
    enemies.push("Mike"); // error: Cannot add property 3
    


    배열의 경우 오류가 실행을 중지합니다! 효과가있다. 이제 개체에 대해 동일한 작업을 수행해 보겠습니다.

    const user = Object.freeze({
      name: "Walter White",
      profession: "Teacher",
      address: {
        city: "Albuquerque",
        state: "NM",
        country: "USA",
      },
    });
    user.profession = "Drug dealer";
    user.address.country = "Brazil";
    console.log(user);
    /*
    {
      name: 'Walter White',
      profession: 'Teacher',
      address: { city: 'Albuquerque', state: 'NM', country: 'Brazil' }
    }
    */
    


    개체의 경우 오류가 발생하지 않고 이상하게 보입니다.

    🙂user.profession는 변함이 없습니다.

    😢 user.address.country 아니...

    왜요?

    얕은 대 깊은 동결



    개체를 고정하면 최상위 속성만 고정됩니다. 즉, 중첩 개체 속성을 변경할 수 있습니다. 즉 shallow freeze 입니다. deep freeze 의 경우 object 유형의 각 속성을 재귀적으로 고정해야 하며 이를 수행하는 도우미 함수를 만들 수 있습니다.

    function deepFreeze(obj) {
      Object.keys(obj).forEach((prop) => {
        const value = obj[prop];
        if (typeof value === "object") deepFreeze(value);
      });
      return Object.freeze(obj);
    }
    
    const user = deepFreeze({
      name: "Walter White",
      profession: "Teacher",
      address: {
        city: "Albuquerque",
        state: "NM",
        country: "USA",
      },
    });
    user.profession = "Drug dealer";
    user.address.country = "Brazil";
    console.log(user);
    /*
    {
      name: 'Walter White',
      profession: 'Teacher',
      address: { city: 'Albuquerque', state: 'NM', country: 'USA' }
    }
    */
    


    이제부터 모든 변경 사항은 새 개체 또는 배열을 생성해야 합니다.

    const user = Object.freeze({
      name: "Walter White",
      profession: "Teacher",
    });
    
    const newUserPropAdded = Object.freeze({
      ...user,
      age: 55,
    });
    console.log(newUserPropAdded);
    // { name: 'Walter White', profession: 'Teacher', age: 55 }
    
    const newUserPropUpdated = Object.freeze({
      ...user,
      profession: "Drug dealer",
    });
    console.log(newUserPropUpdated);
    // { name: 'Walter White', profession: 'Drug dealer' }
    
    const { profession, ...newUserPropDeleted } = user;
    console.log(newUserPropDeleted);
    // { name: 'Walter White' }
    
    console.log('unchanged user :>> ', user);
    // unchanged user :>>  { name: 'Walter White', profession: 'Teacher' }
    



    const enemies = Object.freeze(["Jack Welker", "Gus Fring", "Tuco"]);
    const index = 1;
    
    const newEnemiesItemAdded = [...enemies, "Mike"];
    console.log(newEnemiesItemAdded);
    // [ 'Jack Welker', 'Gus Fring', 'Tuco', 'Mike' ]
    
    const newEnemiesItemUpdated = enemies.map((item, i) =>
      i === index ? "Jesse" : item
    );
    console.log(newEnemiesItemUpdated);
    // [ 'Jack Welker', 'Jesse', 'Tuco' ]
    
    const newEnemiesItemDeleted = [
      ...enemies.slice(0, index),
      ...enemies.slice(index + 1),
    ];
    console.log(newEnemiesItemDeleted);
    // [ 'Jack Welker', 'Tuco' ]
    
    console.log("unchanged enemies :>> ", enemies);
    // unchanged enemies :>>  [ 'Jack Welker', 'Gus Fring', 'Tuco' ]
    


    불변.js



    마지막 팁으로, Immutable.js 라이브러리를 사용하여 Javascript에서 기본이 아닌 데이터 유형의 불변성을 다루는 더 쉬운 방법을 추가할 수도 있습니다.

    결론



    기본이 아닌 데이터 유형이 작동하는 방식을 이해하는 것은 JavaScript에서 올바른 방식으로 데이터를 처리하는 데 매우 중요합니다. 호출 스택과 힙을 기반으로 하는 메모리 모델은 그것의 필수적인 부분이며 당신은 그것을 알아야 합니다.

    좋은 웹페이지 즐겨찾기