LHJ

I'm a FE developer.

22. Abstract Loop & Lazy Execution - 생성자로 data 받기

12 Aug 2020 » codespitz_re

Abstract Loop & Lazy Execution - 생성자로 data 받기

const Compx = class{
    constructor(data) {this.data = data;}
    [Symbol.iterator](){
        const data = JSON.parse(JSON.stringify(this.data));
        return {
            next(){
                let v;
                while (v = data.shift()) {
                    if (!(v instanceof Object)) return {value:v};
                    if (!Array.isArray(v)) v = Object.values(v);
                    data.unshift(...v);
                }
                return {done: true};
            }
        };
    }
};
const a = new Compx([{a:[1,2,3,4], b:'-'}, [5,6,7], 8,9]);

// 여러번 사용할 수 있음
console.log([...a]); // [1,2,3,4,'-',5,6,7,8,9]
console.log([...a]); // [1,2,3,4,'-',5,6,7,8,9]

CLASS는 **생성자로 data를 받아 this.data에 할당한다.

생성자로 받는 data가 Complex data라면?

그리고 iterator에서 이 data가 complex data라고 생각한다면,,

Complex Data란?
배열도아니고 객체도아닌… 여러가지 형태가 섞여있는 Data 유형을 뜻한다.

이런 경우엔 slice() 메서드를 사용할 수도 없고, Object.assign을 사용할 수도 없다.

Object.assign
딥카피 불가능 - 얕은 카피만 가능하다.

딥카피란?

const obj = {a:1, b:2};
const clone = Object.assign(obj);

console.log(clone); // {a:1, b:2}

obj.a = 3;
console.log(obj); // {a:3, b:2};
console.log(clone); // {a:3, b:2}

위와 같은 경우를 얕은 카피라고 부른다.
딥카피라면 위의 obj가 변경되도 clone은 변경이 안되어야 한다.
즉, 딥카피란 ‘참조’가 아닌 ‘값’인 것이다. ‘값을’ 완전히 복사해서 할당하는 개념이다.

즉, 이렇기 때문에 slice()Object.assign도 사용할 수 없다.

생성자로 받는 data가 Complex data이지만 순수 객체라면?

순수객체란 함수도 없고, 특별히 다른 객체가 없다는 뜻이다.
즉, json 처럼 순수하게 인식할 수 있는 data로만 되어있는 객체라고 생각한다면, 이 data를 복사하는 가장 빠른 방법은

const data = JSON.parse(JSON.stringify(this.data));

위 방법이다.
완전히 새롭고 똑같게 복사가된다.
위의 방법은 딥카피보다 훨씬 빠르다.

parsestringify는 C가 처리하기 때문이다.

즉 몇번이고 iterator를 호출해도 원본 data에는 손상이 없다. 항상 사본을 사용하기 때문이다.
이렇게 하기위해 Symbol.iterator를 한번 호출하고 iterator 객체를 받는 것이다.

Symbol.iterator
이를 사용하면 위의 parse, stringify 코드처럼 data 사본을 만들 기회가 생기는 것이다.

그리고 data 사본이 담긴 data라는 자율변수를 사용하기 위해 next 함수를 생성한다.

Tip. ES6+ 문법과 data 유형(배열이 아닌 경우도 있잖아?)

// ES6+는 아래와 같은 구조 : next : function () {} 를
// function을 생략하고 next(){}로 쓸 수 있다.
const Compx = class{
    constructor(data) {this.data = data;}
    [Symbol.iterator](){
        const data = JSON.parse(JSON.stringify(this.data));
        return {
            next: function(){
                let v;
                while (v = data.shift()) {
                    if (!(v instanceof Object)) return {value:v};
                    if (!Array.isArray(v)) v = Object.values(v);
                    data.unshift(...v);
                }
                return {done: true};
            }
        };
    }
};
const a = new Compx([{a:[1,2,3,4], b:'-'}, [5,6,7], 8,9]);
console.log([...a]); // [1,2,3,4,'-',5,6,7,8,9]
console.log([...a]); // [1,2,3,4,'-',5,6,7,8,9]

ES6+는 위와같은 구조를 아래로 변형시켜 쓸 수 있다.

const Compx = class{
    constructor(data) {this.data = data;}
    [Symbol.iterator](){
        const data = JSON.parse(JSON.stringify(this.data));
        return {
            next(){
                let v;
                while (v = data.shift()) {
                    if (!(v instanceof Object)) return {value:v};
                    if (!Array.isArray(v)) v = Object.values(v);
                    data.unshift(...v);
                }
                return {done: true};
            }
        };
    }
};
const a = new Compx([{a:[1,2,3,4], b:'-'}, [5,6,7], 8,9]);
console.log([...a]);
console.log([...a]);

그리고 data가 어떤 유형으로 올지 모르는 경우를 대비해 배열 리터럴로 감싸주면된다.

const Compx = class{
    constructor(data) {this.data = data;}
    [Symbol.iterator](){
        const data = [JSON.parse(JSON.stringify(this.data))];
        return {
            next(){
                let v;
                // 그렇다면 받아들이는 data가 배열일 때만 아래가 처음을 성립하잖아?
                // data가 배열로 시작해야만 shift로 맨앞에 추출하면서 시작할 수 있다.
                // shift는 배열이어야 가능한 메서드
                // 그래서 제일 안전하게는 위의 사본(data)에다가 대괄호를 씌우고 시작하는 것이다.
                // 이 예제가 배열을 받아들여서 뻑이 안 났지만 Object를 받아들였으면 뻑이 났을 거다.
                while (v = data.shift()) {
                    if (!(v instanceof Object)) return {value:v};
                    if (!Array.isArray(v)) v = Object.values(v);
                    data.unshift(...v);
                }
                return {done: true};
            }
        };
    }
};
const a = new Compx([{a:[1,2,3,4], b:'-'}, [5,6,7], 8,9]);
console.log([...a]);
console.log([...a]);