
일단 오늘도 이력서 다듬기를 했는데, 뭔가 지금까지 한 프로젝트들이 잘 정리가 안 되니까 이력서도 어떻게 정리해야 할지 헷갈리는 감이 있다.
그래서 내일은 이력서 말고 포트폴리오를 작업하면서 지금까지 한 프로젝트들을 좀 다시 정리해볼 생각이다.
JavaScript에서 변수에 할당되는 값들은 메모리에 저장이 된다.
이때 실제로 값이 저장되는 방식은, 값이 원시 타입인지, 객체 타입인지에 따라 달라진다.
number, string, boolean, null, undefined 등 타입은 원시 타입이다.
변수 선언: let p1 = 1;
변수 메모리
┌──────┐ ┌──────┐
│ p1 │---->│ 1 │ 메모리 주소: 0x001
└──────┘ └──────┘
복사: let p2 = p1;
변수 메모리
┌──────┐ ┌──────┐
│ p1 │---->│ 1 │ 메모리 주소: 0x001
└──────┘ └──────┘
┌──────┐ ┌──────┐
│ p2 │---->│ 1 │ 메모리 주소: 0x002 (새로운 복사본!)
└──────┘ └──────┘
p2에 p1 값을 할당하면, 메모리상 값이 복사되어 독립적인 메모리에 저장된다.p2와 p1은 서로 영향을 주지 않는다. 재할당: p2 = 2;
변수 메모리
┌──────┐ ┌──────┐
│ p1 │---->│ 1 │ 메모리 주소: 0x001 (변경 없음)
└──────┘ └──────┘
┌──────┐
┌──────┐ │ 1 │ 메모리 주소: 0x002 (버려짐)
│ p2 │-╳ └──────┘
└──────┘ ║ ┌──────┐
╚═=>│ 2 │ 메모리 주소: 0x003 (새 값!)
└──────┘
p2 = 2와 같이 변수에 값을 재할당하더라도, 기존의 값 1은 메모리에서 수정되지 않는다.2가 새로 저장되고, 변수 p2가 새로운 값을 가리킬 뿐이다.object, array, function 등 타입은 객체 타입이다.변수 선언: let o1 = { place: "서울" };
변수 참조값 실제 객체
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o1 │---->│ 0xA001 │----->│ place: "서울" │ 메모리: 0xA001
└──────┘ └────────┘ └─────────────────┘
o1에는 실제 객체를 가리키는 참조값이 저장되며, 실제 데이터는 별도 메모리에 존재한다. 얕은 복사: let o2 = o1;
변수 참조값 실제 객체
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o1 │---->│ 0xA001 │--┐ │ place: "서울" │ 메모리: 0xA001
└──────┘ └────────┘ │ └─────────────────┘
┌──────┐ ┌────────┐ │ ▲
│ o2 │---->│ 0xA001 │--┘ │
└──────┘ └────────┘ │
동일한 객체를 가리킴!
o2에 o1 값을 할당할 때, 메모리상 실제 객체가 아닌 참조값이 복사된다. (얕은 복사)o2와 o1은 동일한 객체를 가리키므로 서로 영향을 줄 수 있다. 값 수정: o2.place = "인천";
변수 참조값 실제 객체
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o1 │---->│ 0xA001 │--┐ │ place: "인천" │ 메모리: 0xA001
└──────┘ └────────┘ │ └─────────────────┘
┌──────┐ ┌────────┐ │ ▲
│ o2 │---->│ 0xA001 │--┘ │
└──────┘ └────────┘ │
둘 다 영향받음!
console.log(o1.place) // "인천"
o2의 place를 인천으로 바꾸면, 실제객체(0xA001)의 데이터가 바뀌므로o1.place도 인천으로 변경된다....(스프레드 연산자)로 깊은 복사를 수행해야 한다. 선언: let o3 = { place: "서울" };
let o4 = { ...o3 };
변수 참조값 실제 객체
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o3 │---->│ 0xB001 │----->│ place: "서울" │ 메모리: 0xB001
└──────┘ └────────┘ └─────────────────┘
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o4 │---->│ 0xB002 │----->│ place: "서울" │ 메모리: 0xB002
└──────┘ └────────┘ └─────────────────┘
(새 객체!)
...(스프레드연산자)는 배열/객체의 여러 값을 개별로 흩뿌려 주는 역할을 수행한다.let o4 = {...o3}로 복사 시, 메모리에 새로운 객체가 생성되며, 프로퍼티만 따로 복사된다. 값 수정: o4.place = "대전";
변수 참조값 실제 객체
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o3 │---->│ 0xB001 │----->│ place: "서울" │ 변경 없음!
└──────┘ └────────┘ └─────────────────┘
┌──────┐ ┌────────┐ ┌─────────────────┐
│ o4 │---->│ 0xB002 │----->│ place: "대전" │ o4만 변경!
└──────┘ └────────┘ └─────────────────┘
o3, o4는 별개 객체를 가리키므로, o4.place를 대전으로 변경해도 o3.place는 변경되지 않는다.
설정: let o5 = { place: "대구" };
let o6 = o5; // 얕은 복사
let o7 = { ...o5 }; // 깊은 복사
[얕은 비교 - 참조값 비교]
o5 === o6 → true
┌────────┐ ┌─────────────────┐
│ 0xC001 │----->│ place: "대구" │
└────────┘ └─────────────────┘
▲ ▲
│ │
o5, o6 모두 같은 참조값!
o5 === o7 → false
┌────────┐ ┌─────────────────┐
│ 0xC001 │----->│ place: "대구" │ o5
└────────┘ └─────────────────┘
┌────────┐ ┌─────────────────┐
│ 0xC002 │----->│ place: "대구" │ o7
└────────┘ └─────────────────┘
참조값이 다름!
o6은 o5와 같은 객체를 가리켜 (동일 참조값) 비교 결과가 true가 된다. o7은 스프레드연산자를 통해 생성된 새로운 객체기 때문에, o5와 프로퍼티의 키/값이 완전히 동일하더라도 참조값이 다르므로 비교 결과가 false가 된다.===를 이용한 참조값 기준 비교를 얕은 비교라고 한다. [깊은 비교 - 내부 값 비교]
JSON.stringify(o5) === JSON.stringify(o7) → true
"{"place":"대구"}" === "{"place":"대구"}"
문자열로 변환하여 내부 값 비교!
JSON.stringify를 사용해 객체의 값을 문자로 변경한 뒤 내부 값을 비교해야 한다. 이를 깊은 비교라고 한다.| 타입 | 저장 방식 | 복사 시 | 수정 시 |
|---|---|---|---|
| 원시 타입 (불변) | 값 자체 저장 | 새 값 복사됨 (독립적) | 새 메모리에 저장 (원본 불변) |
| 객체 타입 (가변) | 참조값 저장 | 참조값 복사됨 (공유됨) | 원본 객체 수정 (모두 영향) |
maplet arr = [1, 2, 3];
let arr_squared = arr.map((item, idx, arr) => {
console.log(`${idx}번째 요소: ${item}`);
return item ** 2;
});
// 0번째 요소: 1
// 1번째 요소: 2
// 2번째 요소: 3
console.log(arr_squared); // [1, 4, 9]
let arr = [
{ name: "롯데리아", category: "햄버거" },
{ name: "김가네", category: "김밥" },
{ name: "설빙", category: "디저트" },
{ name: "맥도날드", category: "햄버거" },
];
let food_names = arr.map((item) => item.name);
console.log(food_names); // [ '롯데리아', '김가네', '설빙', '맥도날드' ]
{users.map(user => <UserCard key={user.id} user={user} />)}
filtertrue인 요소들만 이루어진 새로운 배열을 반환한다.// 콜백함수 결과가 true인 요소들로만 이루어진 새로운 배열 반환
let arr = [
{ name: "롯데리아", category: "햄버거" },
{ name: "김가네", category: "김밥" },
{ name: "설빙", category: "디저트" },
{ name: "맥도날드", category: "햄버거" },
];
console.log(arr.filter((item) => item.category === "햄버거"));
// [ { name: '롯데리아', category: '햄버거' }, { name: '맥도날드', category: '햄버거' } ]
const activeUsers = users.filter(user => user.isActive);
find// 배열에서 콜백함수 결과가 true인 첫 요소를 반환. 없으면 undefined 반환
let arr = [1, 2, 3];
console.log(arr.find((item) => item > 1)); // 2
let objectArr = [{ name: "누렁이" }, { name: "탱고" }, { name: "빵아지" }];
console.log(objectArr.find((item) => item.name === "탱고"));
// { name: '탱고' }
const user = users.find(u => u.id === userId);
slicelet arr = [1, 2, 3, 4, 5];
console.log(arr.slice(1, 4)); // [2, 3, 4] (인덱스 1부터 4 전까지)
console.log(arr.slice(2)); // [3, 4, 5] (인덱스 2부터 끝까지)
console.log(arr.slice(-2)); // [4, 5] (뒤에서부터 2개)
console.log(arr); // [1, 2, 3, 4, 5] (원본 배열은 변경되지 않음)
// 페이지네이션 예시
const currentPage = 2;
const itemsPerPage = 10;
const displayItems = items.slice(
(currentPage - 1) * itemsPerPage,
currentPage * itemsPerPage
);
const newArr = [...arr.slice(0, index), ...arr.slice(index + 1)];
sort/toSorted-1 반환 시 앞 변수, 1 반환 시 뒷 변수가 앞에 오게끔 정렬된다.// 사전순으로 배열 요소를 정렬. 원본 배열이 변경됨
let arr = [5, 10, 3];
arr.sort();
console.log(arr); // [10, 3, 5] (사전순임에 유의)
// 숫자값 기준 시, 비교 콜백함수로 명시해야 함
arr.sort((a, b) => {
if (a > b) {
// 양수 반환 -> 뒤의 매개변수(b)가 먼저 옴
return 1;
} else if (a < b) {
// 음수 반환 -> 앞의 매개변수(a)가 먼저 옴
return -1;
} else {
// 0 반환 -> 두 값의 자리를 바꾸지 않음
return 0;
}
});
console.log(arr); // [3, 5, 10]
let arr_desc = [5, 10, 3];
// 내림차순일 시 그 반대로...
arr_desc.sort((a, b) => {
if (a > b) {
return -1;
} else if (a < b) {
return 1;
} else {
return 0;
}
});
const sorted = [...items].sort((a, b) => a.order - b.order);
toSorted를 사용할 수도 있다.const sorted = items.toSorted((a, b) => a.price - b.price);
내가 다 정리하기 귀찮아서 클로드가 요약해줬다.
| 메서드 | 설명 | 자주 쓰나? | React에서 언제? | 대안 |
|---|---|---|---|---|
findIndex | 조건 만족하는 첫 요소의 인덱스 반환 | ⭐⭐⭐ | 특정 요소 수정/삭제 시 | - |
includes | 특정 요소 포함 여부 확인 | ⭐⭐⭐ | 선택 여부, 권한 체크 | - |
forEach | 모든 요소 순회하며 작업 수행 (반환값 필요 없을 때) | ⭐⭐ | useEffect 내 부수효과 처리 | map 선호 |
join | 배열을 문자열로 결합 | ⭐⭐ | 태그, 주소 등 문자열 표시 | - |
concat | 두 배열 합치기 | ⭐ | 무한 스크롤 데이터 추가 | [...arr1, ...arr2] 선호 |
indexOf | 요소의 인덱스 반환 | ⭐ | 원시값 인덱스 찾기 | includes, findIndex 더 직관적 |
push | 마지막에 요소 추가 (원본 변경) | ❌ | 사용 금지 | [...items, newItem] |
pop | 마지막 요소 제거 (원본 변경) | ❌ | 사용 금지 | items.slice(0, -1) |
shift | 첫 요소 제거 (원본 변경) | ❌ | 사용 금지 | items.slice(1) |
unshift | 첫 요소 추가 (원본 변경) | ❌ | 사용 금지 | [newItem, ...items] |
push, pop, shift, unshift 쓰면 안되는 이유// 올바르지 않은 방법
const [items, setItems] = useState([1, 2, 3]);
const handleAdd = () => {
items.push(4); // 원본 배열 수정
setItems(items); // 같은 참조(주소) -> React는 변화 없다고 판단
};
// 화면이 업데이트되지 않음
// 새로운 배열 생성 - React가 변화 감지
const handleAdd = () => {
setItems([...items, 4]); // 새 배열 생성 -> 다른 참조(주소)
};
// 화면이 정상적으로 업데이트됨
let date1 = new Date(); // 매개변수 없을 시현재 시간
console.log(date1);
// Sat Oct 04 2025 22:17:15 GMT+0900 (한국 표준시)
// 결과는 실행 시점에 따라 다름
let date2 = new Date(2000, 6, 22, 12, 30, 59);
// 월은 0부터 시작함에 유의 (0: 1월, 1: 2월, ..., 6: 7월)
console.log(date2); // Sat Jul 22 2000 12:30:59 GMT+0900 (한국 표준시)
let ts1 = date2.getTime();
console.log(ts1); // 964296659000
// 타임 스탬프로부터 Date 객체 생성 가능
let date3 = new Date(ts1);
console.log(date3); // Sat Jul 22 2000 12:30:59 GMT+0900 (한국 표준시)
get, 수정은 set을 기억하자.// 시간 요소 추출
let year = date2.getFullYear();
let month = date2.getMonth() + 1; // 월은 0부터 시작하므로 +1
let day = date2.getDate();
let hours = date2.getHours();
let minutes = date2.getMinutes();
let seconds = date2.getSeconds();
console.log(
`${year}년 ${month}월 ${day}일 ${hours}시 ${minutes}분 ${seconds}초`
);
// 2000년 7월 22일 12시 30분 59초
// 시간 요소 수정
date2.setFullYear(2025);
date2.setMonth(9); // 10월 (0부터 시작)
date2.setDate(4);
date2.setHours(22);
date2.setMinutes(15);
date2.setSeconds(30);
console.log(date2); // Sat Oct 04 2025 22:15:30 GMT+0900 (한국 표준시)
console.log(date2.toDateString()); // Sat Oct 04 2025
console.log(date2.toLocaleString()); // 2025. 10. 4. 오후 10:15:30
console.log(date2.toLocaleDateString()); // 2025. 10. 4.