본문 바로가기
개발일지/JavaScript ES6

[17] 객체를 이터러블 프로그래밍으로 다루기 (values, entries, keys, object, mapObject, pick, indexBy 및 응용, 그 외)

by 꾸주니=^= 2024. 11. 30.

 

여기서 말하는 객체는 key value 쌍을 말한다.

키: 값

 

이전까지는 iterator를 사용해서 다뤘다.

 

객체를 이터러블 프로그래밍으로 다루는 이유는 코드의 가독성, 유지보수성, 확장성을 높이고 데이터를 효율적으로 처리하기 위해서입니다. 이터러블 프로그래밍은 데이터를 순차적으로 처리하거나 변환하는 작업을 선언적으로 표현할 수 있는 기능을 제공합니다. 객체를 이터러블로 다루는 것은 특히 데이터 구조가 복잡하거나 동적으로 처리해야 할 때 유용합니다.

 

객체와 이터러블의 차이

  • 객체(Object):
    • 키-값 쌍으로 데이터를 표현.
    • 직접적으로 이터레이션(반복)할 수는 없음.
    • JavaScript에서는 객체가 기본적으로 이터러블이 아님.
  • 이터러블(Iterable):
    • 순회 가능한 데이터 구조(예: 배열, 맵, 세트 등).
    • for...of와 같은 구문이나 map, filter 같은 함수형 도구로 처리 가능.

 


 

1. Object.values

  • 설명:
    • 객체의 값들만 추출하여 배열로 반환.
    • 배열 형태로 반환되므로 이터러블 프로그래밍(map, filter)과 결합하여 사용할 수 있음.

 

예제1
const obj = { a: 1, b: 2, c: 3 };

// 값만 추출
const values = Object.values(obj);
console.log(values); // [1, 2, 3]

// 값 중 짝수만 필터링
const evenValues = values.filter(value => value % 2 === 0);
console.log(evenValues); // [2]

 

예제2
const obj1 = { a: 1, b: 2, c: 3 };

L.values = function* (obj) {
    for (const k in obj) {
        yield obj[k]; // 각 키의 값을 순차적으로 반환
    }
};

_.go(
    obj1, // 객체 { a: 1, b: 2, c: 3 }
    L.values, // 지연 평가로 값만 추출: [1, 2, 3]
    L.map(a => a + 10), // 각 값에 10을 더함: [11, 12, 13]
    L.take(2), // 앞에서 두 개의 값만 가져옴: [11, 12]
    _.reduce((a, b) => a + b), // 합계 계산: 11 + 12 = 23
    console.log // 결과 출력: 23
);

L.values는 지연 평가(lazy evaluation)를 사용하여 객체의 값만을 순회(iterate)하는 이터레이터 함수입니다. 객체의 값을 하나씩 순회하면서 yield를 통해 반환하며, 이터러블 프로그래밍 스타일로 데이터를 처리할 수 있도록 지원

 


2. Object.entries

  • 설명:
    • 객체의 키-값 쌍을 배열로 반환. [key, value] 형태의 배열로 변환됨.
    • 키와 값을 동시에 처리하거나 변환 작업에 유용.

 

예제1
const obj = { a: 1, b: 2, c: 3 };

// 키-값 쌍 추출
const entries = Object.entries(obj);
console.log(entries); // [['a', 1], ['b', 2], ['c', 3]]

// 값이 짝수인 키만 필터링
const evenEntries = entries.filter(([key, value]) => value % 2 === 0);
console.log(evenEntries); // [['b', 2]]

// 필터링한 키-값을 다시 객체로 변환
const filteredObj = Object.fromEntries(evenEntries);
console.log(filteredObj); // { b: 2 }

 

예제2
L.entries = function* (obj) {
    for (const k in obj) {
        yield [k, obj[k]]; // 객체의 키-값 쌍을 순차적으로 반환
    }
};

_.go(
    obj1, // { a: 1, b: 2, c: 3 }
    L.entries, // 키-값 쌍 이터레이터 반환: ['a', 1], ['b', 2], ['c', 3]
    L.filter(([_, v]) => v % 2), // 값이 홀수인 항목만 필터링
    L.map(([k, v]) => ({ [k]: v })), // 필터링된 항목을 객체로 변환
    _.reduce(Object.assign), // 객체 병합
    console.log // 최종 결과 출력
);

결과 출력: { a: 1, c: 3 }.

L.entries는 객체의 키-값 쌍을 지연 평가(lazy evaluation)로 반환하는 이터레이터 함수입니다.
기본적으로 Object.entries와 비슷한 기능을 제공하지만, 지연 평가를 통해 효율성을 극대화하며, 이터러블 프로그래밍에 사용할 수 있습니다.

 


3. Object.keys

  • 설명:
    • 객체의 키만 추출하여 배열로 반환.
    • 키 이름으로 작업할 때 유용.

 

예제1
const obj = { a: 1, b: 2, c: 3 };

// 키만 추출
const keys = Object.keys(obj);
console.log(keys); // ['a', 'b', 'c']

// 키가 'b'로 시작하는 항목 필터링
const filteredKeys = keys.filter(key => key.startsWith('b'));
console.log(filteredKeys); // ['b']

 

예제2
L.keys = function* (obj) {
    for (const k in obj) {
        yield k; // 객체의 각 키를 하나씩 반환
    }
};

_.go(
    obj1,        // 초기 객체
    L.keys,      // 객체의 키를 지연 평가로 반환
    _.each(console.log) // 반환된 각 키를 `console.log`로 출력
);

L.keys는 객체의 키를 지연 평가(lazy evaluation)로 반환하는 이터레이터 함수입니다.
기본적으로 Object.keys와 비슷한 기능을 제공하지만, 지연 평가를 통해 효율성을 극대화하며, 이터러블 프로그래밍에 사용할 수 있습니다.


4. Object 생성

  • 설명:
    • 이터러블 데이터를 객체로 변환.
    • 배열이나 키-값 쌍(entries)을 객체로 만들 때 사용.

 

예제1
const entries = [['a', 1], ['b', 2], ['c', 3]];

// 배열을 객체로 변환
const obj = Object.fromEntries(entries);
console.log(obj); // { a: 1, b: 2, c: 3 }

 


5. mapObject

  • 설명:
    • 객체의 각 키-값 쌍을 변환.
    • Lodash 또는 유사한 라이브러리를 사용하거나 직접 구현 가능.

 

예제
const obj = { a: 1, b: 2, c: 3 };

// 키-값 변환
const mapped = Object.fromEntries(
  Object.entries(obj).map(([key, value]) => [key.toUpperCase(), value * 2])
);
console.log(mapped); // { A: 2, B: 4, C: 6 }

 


6. pick

  • 설명:
    • 특정 키를 가진 값들만 추출.
    • Lodash 또는 유사한 라이브러리를 사용하거나 직접 구현 가능.

 

예제
const obj = { a: 1, b: 2, c: 3 };

// 특정 키만 추출
const pick = (obj, keys) =>
  Object.fromEntries(Object.entries(obj).filter(([key]) => keys.includes(key)));

const picked = pick(obj, ['a', 'c']);
console.log(picked); // { a: 1, c: 3 }

 

 


7. indexBy

  • 설명:
    • 배열의 값을 기준으로 객체를 생성.
    • 배열의 특정 값(또는 속성)을 키로 사용해 객체로 변환.

 

예제
const users = [
  { id: 1, name: 'Alice' },
  { id: 2, name: 'Bob' },
  { id: 3, name: 'Charlie' },
];

// id를 기준으로 객체로 변환
const indexedById = users.reduce((acc, user) => {
  acc[user.id] = user;
  return acc;
}, {});

console.log(indexedById);
// {
//   1: { id: 1, name: 'Alice' },
//   2: { id: 2, name: 'Bob' },
//   3: { id: 3, name: 'Charlie' }
// }

 


8. indexBy 된 값을 filter 하기

  • 설명:
    • indexBy로 생성된 객체를 필터링.
    • 객체를 배열로 변환한 뒤 filter를 적용.

 

예제
// 위에서 만든 indexedById 객체
const indexedById = {
  1: { id: 1, name: 'Alice' },
  2: { id: 2, name: 'Bob' },
  3: { id: 3, name: 'Charlie' },
};

// 이름이 'A'로 시작하는 사용자만 필터링
const filtered = Object.values(indexedById).filter(user => user.name.startsWith('A'));
console.log(filtered); // [{ id: 1, name: 'Alice' }]

 


9. 어떠한 값이든 이터러블 프로그래밍으로 다루기

  • 설명:
    • 이터러블 프로그래밍의 기본 원칙을 적용해 객체, 배열, 또는 기타 데이터를 선언적으로 처리.

 

예제
const data = {
  users: [
    { id: 1, name: 'Alice', age: 25 },
    { id: 2, name: 'Bob', age: 30 },
    { id: 3, name: 'Charlie', age: 35 },
  ],
};

// 이름만 추출
const names = data.users.map(user => user.name);
console.log(names); // ['Alice', 'Bob', 'Charlie']

// 나이가 30 이상인 사용자만 추출
const olderUsers = data.users.filter(user => user.age >= 30);
console.log(olderUsers);
// [{ id: 2, name: 'Bob', age: 30 }, { id: 3, name: 'Charlie', age: 35 }]

// 특정 사용자 객체로 변환
const indexedByName = data.users.reduce((acc, user) => {
  acc[user.name] = user;
  return acc;
}, {});
console.log(indexedByName);
// {
//   Alice: { id: 1, name: 'Alice', age: 25 },
//   Bob: { id: 2, name: 'Bob', age: 30 },
//   Charlie: { id: 3, name: 'Charlie', age: 35 }
// }