Computer >> 컴퓨터 >  >> 프로그래밍 >> JavaScript

자바스크립트에서 문자열을 중첩된 계층 객체로 변환하는 방법

문제 상황

두 글자씩 짝지어진 특수한 형태의 문자열이 있다고 가정해 보겠습니다.

const str = "AABBCCDDEE";

이 문자열을 기반으로 아래와 같은 중첩(nested) 구조의 객체를 만들어야 합니다.

const obj = {
    code: "AA",
    sub: {
        code: "BB",
        sub: {
            code: "CC",
            sub: {
                code: "DD",
                sub: {
                    code: "EE",
                    sub: {}
                }
            }
        }
    }
};

여기서 주목할 점은, 문자열의 각 두 글자 쌍마다 새로운 sub 객체가 생성되며, 각 계층의 code 속성은 해당 위치의 두 글자 쌍을 그대로 담고 있다는 것입니다.

해결 접근 방식

이 문제는 반복(iterative) 방식으로 해결할 수 있습니다. while 루프를 사용해 문자열을 순회하면서 앞에서부터 두 글자씩 잘라내고, 잘라낸 값을 code 속성에 할당한 뒤 참조 변수를 새로 만든 sub 객체로 이동시키는 방식입니다.

핵심은 ref라는 임시 참조 변수입니다. 처음에는 결과 객체 res 자체를 가리키다가, 루프가 한 번 돌 때마다 새로 생성된 sub 객체를 가리키도록 갱신됩니다. 덕분에 재귀 함수 호출 없이도 깊이 중첩된 구조를 간단하게 만들 수 있습니다.

예제 코드

const str = "AABBCCDDEE";
const constructObject = str => {
    const res = {};
    let ref = res;
    while(str){
        const words = str.substring(0, 2);
        str = str.substr(2, str.length);
        ref.code = words;
        ref.sub = {};
        ref = ref.sub;
    };
    return res;
};
console.log(JSON.stringify(constructObject(str), undefined, 4));

실행 결과

위 코드를 실행하면 콘솔에 다음과 같은 출력이 나타납니다.

{
    "code": "AA",
    "sub": {
        "code": "BB",
        "sub": {
            "code": "CC",
            "sub": {
                "code": "DD",
                "sub": {
                    "code": "EE",
                    "sub": {}
                }
            }
        }
    }
}

코드 동작 원리와 개선 팁

substring(0, 2)는 문자열의 맨 앞 두 글자를 추출하고, substr(2, str.length)는 이미 처리된 부분을 제거한 나머지 문자열을 반환합니다. 루프는 문자열이 빈 값이 될 때까지 반복되므로, 마지막 계층에는 항상 빈 객체인 sub: {}가 남게 되는 구조입니다.

참고로 String.prototype.substr()은 현재 폐지 예정(deprecated) 상태이므로, 실무 코드에서는 slice() 메서드를 사용하는 것이 더 안전합니다. slice() 기반으로 리팩터링하면 다음과 같습니다.

const constructObject = str => {
    const res = {};
    let ref = res;
    while(str.length){
        ref.code = str.slice(0, 2);
        str = str.slice(2);
        ref.sub = {};
        ref = ref.sub;
    }
    return res;
};