본문 바로가기
Javascript

자바스크립트 공부3 - 배열과 객체 다루기

by 겨니2 2025. 5. 27.

reduce

배열을 단일 값으로 줄이는 메서드

 

합계
const grades = [1, 2, 3];

const sum = grades.reduce((total, current) => { 
    return total + current;
}, 0);

total, current 2개의 매개변수를 사용합니다.

total은 reduce가 항상 마지막으로 계산한 값을 참조합니다.

current는 지금 처리할 항목입니다.

 

0을 넣는 이유

  • 첫 번째 루프에서 total 변수에 할당될 값을 정의하는 것입니다.
  • 빈 배열을 대상으로 할 경우 초기값이 없으면 TypeError가 발생됩니다.
  • 초기값 없이 첫 번째 요소부터 시작하면, 첫 번째 요소가 누락되거나 불필요한 조건 검사를 추가해야 할 수도 있습니다.

 

곱셈
const numbers = [1, 2, 3];

const result = numbers.reduce((total, current) => {
    return total * current;
}, 1);

 

곱셉을 할 때는 시작 값을 1로 지정합니다.

초기값이 0이면 곱하는 값이 0이 되어 버리기 때문입니다.


객체 키/값 접근, 복사, 병합

접근
  • 점 표기
const user = {
    id: 1,
    firstName: "Jane",
    lastName: "Kwon",
    age: 35
};

user.firstName = "Lily";
user.age = user.age + 1;
console.log(user); // {id: 1, firstName: "Jane", lastName: "Kwon", age: 36}
function getPhoneNumber(user) {
    return `${user.name}'s phone number is ${user.phone}.`
}

console.log(getPhoneNumber({user: "Jane", phone: "010-1111-2222"})); 
// "Jane's phone number is 010-1111-2222."

console.log(getPhoneNumber({user: "Lily", phone: "010-3333-4444"})); 
// "Lily's phone number is 010-3333-4444."

 

const로 정의된 객체의 속성 값을 업데이트할 수 있다고 해서 변수가 상수라는 의미는 아니며 단지 재할당할 수 없다는 의미입니다.

따라서 변수는 항상 객체이지만, 그 내용(속성)은 변경될 수 있습니다.

const user = {
    id: 1,
    firstName: "Sam",
    lastName: "Doe",
    age: 20
};

user.lastName = "Blue";
user.age = user.age + 1;
console.log(user); // {id: 1, firstName: "Sam", lastName: "Blue", age: 21}
  • Object.keys()
const user = { name: 'Jane', age: 35, gender: 'female' };
const keys = Object.keys(user);
console.log(keys); // [ 'name', 'age', 'gender' ]
  • Object.values()
const values = Object.values(user);
console.log(values); // [ 'Jane', 35, 'female' ]
  • Object.entries()
const entries = Object.entries(user);
console.log(entries); // [ [ 'name', 'Jane' ], [ 'age', 35 ], [ 'gender', 'female' ] ]

 

복사

 

얕은 복사 

- 객체의 첫 번째 수준에 있는 값만 복사하는 방식

- 복사본과 원본이 같은 참조를 공유하게 됨

- 복사본을 변경하면 원본도 함께 변경됨

 

깊은 복사

- 객체 내부의 모든 값을 완전히 복사하여 새로운 메모리 공간에 할당하는 방식

- 객체의 실제 값 자체를 복사함

- 참조가 완전히 끊어진 독립적인 객체 생성

- 복사본을 변경해도 원본에 영향을 주지 않음

 

  • 할당 연산자(=)

복사된 객체를 변경하면 원본 객체도 변경됩니다.

let original = { a: 1 };
let copy = original;
copy.a = 2;
console.log(original.a); // 2
  • Object.assign()

얕은 복사를 할 수 있습니다. 객체 내부의 객체나 배열은 참조만 복사됩니다.

let original = { a: 1, b: { c: 2 } };
let copy = Object.assign({}, original);
copy.b.c = 3;
console.log(original.b.c); // 3
  • 스프레드 연산자( {...} )

얕은 복사를 할 수 있습니다.

let original = { a: 1, b: { c: 2 } };
let copy = { ...original };
copy.b.c = 3;
console.log(original.b.c); // 3
  • JSON 직렬화 및 역직렬화

깊은 복사를 할 수 있습니다. 하지만 함수나 undefined, Symbole 등을 처리할 수 없습니다.

let original = { a: 1, b: { c: 2 } };
let copy = JSON.parse(JSON.stringify(original));
copy.b.c = 3;
console.log(original.b.c); // 2
  • 깊은 복사 라이브러리

lodash와 같은 라이브러리를 사용하면 더 복잡한 객체의 깊은 복사를 쉽게 할 수 있습니다.

const _ = require('lodash');
let original = { a: 1, b: { c: 2 } };
let copy = _.cloneDeep(original);
copy.b.c = 3;
console.log(original.b.c); // 2
  • 수동 깊은 복사

재귀 함수를 사용하여 수동으로 깊은 복사를 구현할 수도 있습니다.

function deepCopy(obj) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    let copy = Array.isArray(obj) ? [] : {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            copy[key] = deepCopy(obj[key]);
        }
    }
    return copy;
}

let original = { a: 1, b: { c: 2 } };
let copy = deepCopy(original);
copy.b.c = 3;
console.log(original.b.c); // 2

 

병합
  • Object.assign()

중첩된 객체는 덮어쓰기가 되는 얕은 병합을 할 수 있습니다.

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { b: { d: 3 }, e: 4 };
let merged = Object.assign({}, obj1, obj2);
console.log(merged); // { a: 1, b: { d: 3 }, e: 4 }
  • 스프레드 연산자( {...} )

얕은 병합을 할 수 있습니다.

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { b: { d: 3 }, e: 4 };
let merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: { d: 3 }, e: 4 }
  • 수동 깊은 병합

재귀 함수를 사용하여 중찹된 객체를 병합해야 합니다.

function deepMerge(target, source) {
    for (const key in source) {
        if (source[key] instanceof Object && key in target) {
            Object.assign(source[key], deepMerge(target[key], source[key]));
        }
        target[key] = source[key];
    }
    return target;
}

let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { b: { d: 3 }, e: 4 };
let merged = deepMerge({}, obj1);
deepMerge(merged, obj2);
console.log(merged); // { a: 1, b: { c: 2, d: 3 }, e: 4 }
  • lodash의 merge()

깊은 병합

const _ = require('lodash');
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { b: { d: 3 }, e: 4 };
let merged = _.merge({}, obj1, obj2);
console.log(merged); // { a: 1, b: { c: 2, d: 3 }, e: 4 }
  • ramda의 mergeDeepRight()

깊은 병합

const R = require('ramda');
let obj1 = { a: 1, b: { c: 2 } };
let obj2 = { b: { d: 3 }, e: 4 };
let merged = R.mergeDeepRight(obj1, obj2);
console.log(merged); // { a: 1, b: { c: 2, d: 3 }, e: 4 }