자바스크립트로 개발을 하다 보면 객체나 배열을 복사해야 하는 상황이 자주 발생합니다. 특히 React나 Node.js 애플리케이션에서는 데이터의 불변성(immutability)을 유지하기 위해 원본 데이터를 직접 수정하지 않고 복사본을 만들어 작업하는 것이 중요합니다. 이때 '얕은 복사(Shallow Copy)'와 '깊은 복사(Deep Copy)'의 차이를 이해하는 것이 매우 중요한데요, 이 두 개념을 쉽게 이해해 봅시다! 👨💻👩💻
import _ from 'lodash';
const original = {
user: { name: "철수", hobbies: ["축구", "게임"] },
created: new Date()
};
const deepCopied = _.cloneDeep(original);
// 모든 수준의 변경이 안전함!
deepCopied.user.hobbies.push("코딩");
console.log(original.user.hobbies); // ["축구", "게임"] ✅
3. React에서 중첩 객체 복사하기 (함수형 접근)
// React에서 상태 업데이트 시 중첩 객체 안전하게 수정하기
const updateUserHobby = (user) => {
return {
...user,
hobbies: [...user.hobbies, "코딩"],
info: { ...user.info, age: user.info.age + 1 }
};
};
JSON 방식의 깊은 복사 주의점 ⚠️
JSON을 이용한 깊은 복사는 간단하지만 몇 가지 제한이 있습니다
함수, Map, Set, Date 객체 등은 제대로 복사되지 않음
undefined와 같은 특수값이 손실될 수 있음
순환 참조(Circular Reference)가 있으면 오류 발생
실전 사용 예시: React에서 중첩된 상태 업데이트 🔄
React에서는 상태의 불변성을 유지하는 것이 중요합니다. 다음은 중첩된 객체를 안전하게 업데이트하는 예시입니다:
function ProfileEditor() {
const [user, setUser] = useState({
name: "김철수",
contact: { email: "chulsoo@example.com", phone: "010-1234-5678" },
tags: ["개발자", "리액트"]
});
// 중첩된 속성 업데이트 (깊은 복사 원리 활용)
const updateEmail = (newEmail) => {
setUser({
...user, // 1단계 얕은 복사
contact: { // contact 객체 새로 생성
...user.contact, // 기존 contact 속성 복사
email: newEmail // email만 업데이트
}
});
};
}
얕은 복사 vs 깊은 복사: 언제 무엇을 사용할까? 🤔
얕은 복사가 적합한 경우
단순한 구조의 객체를 다룰 때
성능이 중요하고 중첩 객체를 수정할 일이 없을 때
의도적으로 참조를 공유하고 싶을 때
깊은 복사가 적합한 경우
복잡한 중첩 구조의 객체를 안전하게 복사할 때
원본 데이터의 불변성을 완벽하게 유지해야 할 때
React, Redux 등에서 상태 관리 시
정리 📝
얕은 복사: 최상위 속성만 새로 복사, 중첩 객체는 참조 공유 🌊
깊은 복사: 모든 중첩 수준까지 완전히 새로 복사 🏊♂️
주의점: 복사 방법에 따라 사이드 이펙트가 발생할 수 있음 ⚠️
자바스크립트에서 객체와 배열을 다룰 때, 얕은 복사와 깊은 복사의 차이를 이해하는 것은 버그를 예방하고 코드의 예측 가능성을 높이는 데 매우 중요합니다. 특히 React나 Redux와 같은 프레임워크에서는 상태의 불변성을 유지하기 위해 이 개념을 제대로 이해하고 있어야 합니다! 💪
cron과 node-schedule은 Node.js 애플리케이션에서 정해진 시간에 특정 작업을 실행할 수 있게 해주는 스케줄링 라이브러리입니다. 이메일 발송, 데이터베이스 백업, 알림 전송 등 주기적으로 수행해야 하는 작업에 매우 유용합니다.
주요 차이점
1. 문법과 사용 방식
cron은 유닉스 crontab 문법을 직접적으로 사용합니다:
const cron = require('cron');
// 매일 오전 10시 30분에 실행
const job = new cron.CronJob('30 10 * * *', function() {
console.log('매일 오전 10시 30분에 실행되는 작업입니다.');
});
job.start();
node-schedule은 더 유연한 자바스크립트 객체 기반 문법을 제공합니다:
const schedule = require('node-schedule');
// 매일 오전 10시 30분에 실행
const job = schedule.scheduleJob('30 10 * * *', function() {
console.log('매일 오전 10시 30분에 실행되는 작업입니다.');
});
2. 기능의 차이
node-schedule:
날짜 객체를 직접 사용할 수 있음
복잡한 스케줄링 규칙 지원
작업 취소 및 재스케줄링이 편리함
cron:
더 가벼운 라이브러리
유닉스 crontab 문법에 익숙한 사용자에게 직관적
타임존 지원이 내장되어 있음
3. 날짜 객체 사용 예시
node-schedule에서는 Date 객체를 직접 사용할 수 있습니다:
const schedule = require('node-schedule');
// 특정 날짜와 시간에 실행
const date = new Date(2025, 2, 20, 15, 30, 0);
const job = schedule.scheduleJob(date, function() {
console.log('2025년 3월 20일 오후 3시 30분에 실행됩니다.');
});
cron에서는 Date 객체를 직접 사용할 수 없고, cron 표현식을 사용해야 합니다:
const cron = require('cron');
// 특정 날짜와 시간을 cron 표현식으로 표현해야 함
const job = new cron.CronJob('0 30 15 20 3 *', function() {
console.log('2025년 3월 20일 오후 3시 30분에 실행됩니다.');
}, null, true, 'Asia/Seoul');
실제 사용 예시: 일일 보고서 생성
cron을 사용한 예시
const cron = require('cron');
const fs = require('fs');
// 매일 밤 12시에 보고서 생성
const dailyReport = new cron.CronJob('0 0 0 * * *', function() {
const today = new Date();
const reportData = `일일 보고서 - ${today.toLocaleDateString()}`;
fs.writeFile(`report-${today.toISOString().split('T')[0]}.txt`, reportData, (err) => {
if (err) throw err;
console.log('일일 보고서가 생성되었습니다.');
});
}, null, true, 'Asia/Seoul');
dailyReport.start();
두 라이브러리 모두 Node.js에서 작업 스케줄링을 위한 훌륭한 도구입니다. 간단한 주기적 작업이라면 어떤 라이브러리를 선택하든 큰 차이가 없지만, 프로젝트의 특성과 개발자의 선호도에 따라 선택하면 됩니다. cron은 유닉스 스타일의 간결한 문법을 제공하고, node-schedule은 더 유연하고 자바스크립트 친화적인 인터페이스를 제공합니다.
초보자의 경우, 자바스크립트 객체를 직접 다룰 수 있는 node-schedule이 조금 더 이해하기 쉬울 수 있습니다. 하지만 장기적으로는 두 라이브러리의 문법을 모두 알아두면 다양한 상황에 대응할 수 있습니다.