JavaScript 배열과 객체 | Array, Object 메서드 완벽 정리
이 글의 핵심
JavaScript 배열과 객체: Array, Object 메서드 배열 (Array)·객체 (Object).
들어가며
배열과 객체
배열(Array)은 순서가 있는 값의 목록이고, 객체(Object)는 이름(키)으로 값을 묶은 맵에 가깝습니다. 둘 다 동적이므로 실행 중에 요소·속성을 자유롭게 넣고 빼는 패턴이 흔합니다.
실전 경험에서 배운 교훈
이 기술을 실무 프로젝트에 처음 도입했을 때, 공식 문서만으로는 알 수 없었던 많은 함정들이 있었습니다. 특히 프로덕션 환경에서 발생하는 엣지 케이스들은 로컬 개발 환경에서는 재현조차 되지 않았죠.
가장 어려웠던 점은 성능 최적화였습니다. 처음엔 “동작만 하면 되겠지”라고 생각했지만, 실제 사용자 트래픽이 몰리면서 병목 지점들이 하나씩 드러났습니다. 특히 데이터베이스 쿼리 최적화, 캐싱 전략, 에러 핸들링 구조 등은 여러 번의 장애를 겪으면서 개선해 나갔습니다.
이 글에서는 그런 시행착오를 통해 얻은 실전 노하우와, “이렇게 하면 안 된다”는 교훈들을 함께 정리했습니다. 특히 트러블슈팅 섹션은 실제 장애 대응 경험을 바탕으로 작성했으니, 비슷한 문제를 마주했을 때 참고하시면 도움이 될 것입니다.
1. 배열 (Array)
배열 생성과 접근
// 배열 생성
let fruits = ["apple", "banana", "cherry"];
let numbers = [1, 2, 3, 4, 5];
let mixed = [1, "hello", true, null, { name: "홍길동" }];
// 빈 배열
let empty1 = [];
let empty2 = new Array();
// 특정 크기 배열
let arr = new Array(5); // [empty × 5]
console.log(arr.length); // 5
// 인덱싱 (0부터 시작)
console.log(fruits[0]); // apple
console.log(fruits[1]); // banana
console.log(fruits[-1]); // undefined (음수 인덱스 없음)
// 마지막 요소
console.log(fruits[fruits.length - 1]); // cherry
// 수정
fruits[1] = "grape";
console.log(fruits); // ['apple', 'grape', 'cherry']
배열 메서드: 추가/삭제
let arr = [1, 2, 3];
// push: 끝에 추가
arr.push(4);
console.log(arr); // [1, 2, 3, 4]
// pop: 끝에서 제거
let last = arr.pop();
console.log(last); // 4
console.log(arr); // [1, 2, 3]
// unshift: 앞에 추가
arr.unshift(0);
console.log(arr); // [0, 1, 2, 3]
// shift: 앞에서 제거
let first = arr.shift();
console.log(first); // 0
console.log(arr); // [1, 2, 3]
// splice: 중간 삽입/삭제
arr.splice(1, 1); // 인덱스 1에서 1개 제거
console.log(arr); // [1, 3]
arr.splice(1, 0, 2); // 인덱스 1에 2 삽입
console.log(arr); // [1, 2, 3]
arr.splice(1, 1, 10, 20); // 인덱스 1에서 1개 제거하고 10, 20 삽입
console.log(arr); // [1, 10, 20, 3]
배열 메서드: 검색
let numbers = [1, 2, 3, 4, 5, 3];
// indexOf: 첫 번째 인덱스
console.log(numbers.indexOf(3)); // 2
console.log(numbers.indexOf(10)); // -1 (없음)
// lastIndexOf: 마지막 인덱스
console.log(numbers.lastIndexOf(3)); // 5
// includes: 존재 여부 (ES2016+)
console.log(numbers.includes(3)); // true
console.log(numbers.includes(10)); // false
// find: 조건에 맞는 첫 요소
let found = numbers.find(x => x > 3);
console.log(found); // 4
// findIndex: 조건에 맞는 첫 인덱스
let index = numbers.findIndex(x => x > 3);
console.log(index); // 3
// some: 하나라도 조건 만족
console.log(numbers.some(x => x > 4)); // true
// every: 모두 조건 만족
console.log(numbers.every(x => x > 0)); // true
console.log(numbers.every(x => x > 2)); // false
배열 메서드: 변환
배열을 변환하는 핵심 메서드들입니다:
let numbers = [1, 2, 3, 4, 5];
// 1. map: 각 요소를 변환하여 새 배열 생성
let doubled = numbers.map(x => x * 2);
// 동작:
// [1, 2, 3, 4, 5]
// ↓ ↓ ↓ ↓ ↓ 각 요소에 함수 적용
// [2, 4, 6, 8, 10]
//
// 원본 배열은 변경되지 않음 (불변성)
console.log(doubled); // [2, 4, 6, 8, 10]
console.log(numbers); // [1, 2, 3, 4, 5] (원본 유지)
// map 실전 예시: 객체 배열 변환
let users = [
{ name: "홍길동", age: 25 },
{ name: "김철수", age: 30 }
];
let names = users.map(user => user.name);
console.log(names); // ['홍길동', '김철수']
// 2. filter: 조건을 만족하는 요소만 선택
let evens = numbers.filter(x => x % 2 === 0);
// 동작:
// [1, 2, 3, 4, 5]
// ↓ ✓ ↓ ✓ ↓ 조건 체크 (짝수만 통과)
// [2, 4]
console.log(evens); // [2, 4]
// filter 실전 예시: 성인만 필터링
let adults = users.filter(user => user.age >= 20);
// 3. reduce: 배열을 하나의 값으로 축약
let sum = numbers.reduce((acc, x) => acc + x, 0);
// acc: 누적값 (accumulator)
// x: 현재 요소
// 0: 초기값
//
// 동작 과정:
// acc=0, x=1 → 0+1=1
// acc=1, x=2 → 1+2=3
// acc=3, x=3 → 3+3=6
// acc=6, x=4 → 6+4=10
// acc=10, x=5 → 10+5=15
console.log(sum); // 15
// reduce로 평균 계산
let avg = numbers.reduce((acc, x, i, arr) => {
// acc: 누적값
// x: 현재 요소
// i: 현재 인덱스
// arr: 원본 배열
acc += x;
// 마지막 요소면 평균 계산
return i === arr.length - 1 ? acc / arr.length : acc;
}, 0);
console.log(avg); // 3
// reduce로 객체 변환 (배열 → 객체)
let words = ["apple", "banana", "cherry"];
let wordLengths = words.reduce((acc, word) => {
// acc: 누적 객체 (처음엔 빈 객체 {})
// word: 현재 문자열
acc[word] = word.length; // 객체에 프로퍼티 추가
return acc; // 누적 객체 반환
}, {});
console.log(wordLengths);
// { apple: 5, banana: 6, cherry: 6 }
// reduce로 최댓값 찾기
let max = numbers.reduce((acc, x) => Math.max(acc, x));
console.log(max); // 5
// reduce로 배열 평탄화
let nested = [[1, 2], [3, 4], [5]];
let flattened = nested.reduce((acc, arr) => acc.concat(arr), []);
console.log(flattened); // [1, 2, 3, 4, 5]
메서드 체이닝:
// map, filter, reduce를 연결하여 사용
// 변수 선언 및 초기화
let result = numbers
.filter(x => x > 2) // [3, 4, 5]
.map(x => x * 2) // [6, 8, 10]
.reduce((a, b) => a + b, 0); // 24
console.log(result); // 24
원본 배열 변경 여부:
- 변경함:
push,pop,shift,unshift,splice,sort,reverse - 변경 안 함:
map,filter,reduce,slice,concat
배열 메서드: 정렬
let numbers = [3, 1, 4, 1, 5, 9, 2];
// sort: 원본 변경
numbers.sort();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 9]
// 내림차순
numbers.sort((a, b) => b - a);
console.log(numbers); // [9, 5, 4, 3, 2, 1, 1]
// 문자열 정렬
let words = ["banana", "apple", "cherry"];
words.sort();
console.log(words); // ['apple', 'banana', 'cherry']
// 객체 배열 정렬
let users = [
{ name: "홍길동", age: 25 },
{ name: "김철수", age: 30 },
{ name: "이영희", age: 20 }
];
users.sort((a, b) => a.age - b.age);
console.log(users);
// [{ name: '이영희', age: 20 }, ...]
// reverse: 역순
numbers.reverse();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 9]
배열 메서드: 기타
let arr = [1, 2, 3, 4, 5];
// slice: 부분 배열 (원본 유지)
let sub = arr.slice(1, 4);
console.log(sub); // [2, 3, 4]
console.log(arr); // [1, 2, 3, 4, 5] (원본 유지)
// concat: 배열 연결
let arr1 = [1, 2];
let arr2 = [3, 4];
let combined = arr1.concat(arr2);
console.log(combined); // [1, 2, 3, 4]
// join: 문자열로 변환
let joined = arr.join(", ");
console.log(joined); // 1, 2, 3, 4, 5
// flat: 평탄화 (ES2019+)
let nested = [1, [2, 3], [4, [5, 6]]];
console.log(nested.flat()); // [1, 2, 3, 4, [5, 6]]
console.log(nested.flat(2)); // [1, 2, 3, 4, 5, 6]
console.log(nested.flat(Infinity)); // [1, 2, 3, 4, 5, 6]
// flatMap: map + flat
let words = ["hello world", "foo bar"];
let chars = words.flatMap(word => word.split(" "));
console.log(chars); // ['hello', 'world', 'foo', 'bar']
2. 객체 (Object)
객체 생성과 접근
// 객체 리터럴
let person = {
name: "홍길동",
age: 25,
city: "서울"
};
// 빈 객체
let empty = {};
// 접근
console.log(person.name); // 홍길동 (점 표기법)
console.log(person[age]); // 25 (대괄호 표기법)
// 동적 키
let key = "city";
console.log(person[key]); // 서울
// 추가/수정
person.job = "개발자"; // 추가
person.age = 26; // 수정
console.log(person);
// { name: '홍길동', age: 26, city: '서울', job: '개발자' }
// 삭제
delete person.city;
console.log(person);
// { name: '홍길동', age: 26, job: '개발자' }
객체 메서드
let person = {
name: "홍길동",
age: 25,
greet: function() {
console.log(`안녕하세요, ${this.name}입니다.`);
},
// 축약 문법 (ES6+)
introduce() {
console.log(`${this.age}살 ${this.name}입니다.`);
}
};
person.greet(); // 안녕하세요, 홍길동입니다.
person.introduce(); // 25살 홍길동입니다.
Object 정적 메서드
let person = { name: "홍길동", age: 25, city: "서울" };
// Object.keys(): 키 배열
console.log(Object.keys(person));
// ['name', 'age', 'city']
// Object.values(): 값 배열
console.log(Object.values(person));
// ['홍길동', 25, '서울']
// Object.entries(): [키, 값] 배열
console.log(Object.entries(person));
// [['name', '홍길동'], ['age', 25], ['city', '서울']]
// 순회
for (let [key, value] of Object.entries(person)) {
console.log(`${key}: ${value}`);
}
// Object.assign(): 객체 병합
let defaults = { theme: "dark", lang: "ko" };
let userSettings = { lang: "en" };
let settings = Object.assign({}, defaults, userSettings);
console.log(settings); // { theme: 'dark', lang: 'en' }
// Object.freeze(): 불변 객체
let frozen = Object.freeze({ x: 10 });
frozen.x = 20; // 무시됨
console.log(frozen.x); // 10
// Object.seal(): 추가/삭제 불가, 수정 가능
let sealed = Object.seal({ x: 10 });
sealed.x = 20; // OK
sealed.y = 30; // 무시됨
console.log(sealed); // { x: 20 }
3. 구조 분해 (Destructuring)
배열 구조 분해
let arr = [1, 2, 3, 4, 5];
// 기본
let [a, b] = arr;
console.log(a, b); // 1 2
// 나머지
let [first, ...rest] = arr;
console.log(first); // 1
console.log(rest); // [2, 3, 4, 5]
// 건너뛰기
let [x, , z] = arr;
console.log(x, z); // 1 3
// 기본값
let [p, q, r, s, t, u = 0] = arr;
console.log(u); // 0
// 스왑
let [m, n] = [10, 20];
[m, n] = [n, m];
console.log(m, n); // 20 10
객체 구조 분해
let person = { name: "홍길동", age: 25, city: "서울" };
// 기본
let { name, age } = person;
console.log(name, age); // 홍길동 25
// 새 변수명
let { name: userName, age: userAge } = person;
console.log(userName, userAge); // 홍길동 25
// 기본값
let { name, age, job = "없음" } = person;
console.log(job); // 없음
// 나머지
let { name, ...rest } = person;
console.log(name); // 홍길동
console.log(rest); // { age: 25, city: '서울' }
// 중첩 구조 분해
let user = {
id: 1,
profile: {
name: "홍길동",
age: 25
}
};
let { profile: { name, age } } = user;
console.log(name, age); // 홍길동 25
함수 매개변수 구조 분해
// 객체 구조 분해
function printUser({ name, age, city = "서울" }) {
console.log(`${name} (${age}세, ${city})`);
}
printUser({ name: "홍길동", age: 25 });
// 홍길동 (25세, 서울)
// 배열 구조 분해
function getMinMax([first, ...rest]) {
return {
min: Math.min(first, ...rest),
max: Math.max(first, ...rest)
};
}
console.log(getMinMax([3, 1, 4, 1, 5]));
// { min: 1, max: 5 }
4. Spread와 Rest 연산자
Spread 연산자 (…)
// 배열 펼치기
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let combined = [...arr1, ...arr2];
console.log(combined); // [1, 2, 3, 4, 5, 6]
// 배열 복사
let original = [1, 2, 3];
let copy = [...original];
copy[0] = 100;
console.log(original); // [1, 2, 3] (원본 유지)
console.log(copy); // [100, 2, 3]
// 함수 인자로 펼치기
function add(a, b, c) {
return a + b + c;
}
let numbers = [1, 2, 3];
console.log(add(...numbers)); // 6
// 객체 펼치기 (ES2018+)
let obj1 = { a: 1, b: 2 };
let obj2 = { c: 3, d: 4 };
let merged = { ...obj1, ...obj2 };
console.log(merged); // { a: 1, b: 2, c: 3, d: 4 }
// 객체 복사
let person = { name: "홍길동", age: 25 };
let personCopy = { ...person };
personCopy.age = 26;
console.log(person.age); // 25 (원본 유지)
console.log(personCopy.age); // 26
// 속성 덮어쓰기
let defaults = { theme: "dark", lang: "ko" };
let userSettings = { ...defaults, lang: "en" };
console.log(userSettings); // { theme: 'dark', lang: 'en' }
Rest 연산자
// 함수 매개변수
function sum(...numbers) {
return numbers.reduce((acc, x) => acc + x, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
// 배열 구조 분해
let [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first); // 1
console.log(second); // 2
console.log(rest); // [3, 4, 5]
// 객체 구조 분해
let { name, ...otherInfo } = { name: "홍길동", age: 25, city: "서울" };
console.log(name); // 홍길동
console.log(otherInfo); // { age: 25, city: '서울' }
5. 배열 고급 메서드
forEach vs map
let numbers = [1, 2, 3];
// forEach: 반환값 없음
numbers.forEach(x => console.log(x * 2));
// 2 4 6
// map: 새 배열 반환
let doubled = numbers.map(x => x * 2);
console.log(doubled); // [2, 4, 6]
reduce 심화
let numbers = [1, 2, 3, 4, 5];
// 합계
let sum = numbers.reduce((acc, x) => acc + x, 0);
console.log(sum); // 15
// 최대값
let max = numbers.reduce((acc, x) => Math.max(acc, x));
console.log(max); // 5
// 빈도수 세기
let words = ["apple", "banana", "apple", "cherry", "banana", "apple"];
let frequency = words.reduce((acc, word) => {
acc[word] = (acc[word] || 0) + 1;
return acc;
}, {});
console.log(frequency);
// { apple: 3, banana: 2, cherry: 1 }
// 배열을 객체로
let users = [
{ id: 1, name: "홍길동" },
{ id: 2, name: "김철수" }
];
let userMap = users.reduce((acc, user) => {
acc[user.id] = user;
return acc;
}, {});
console.log(userMap);
// { 1: { id: 1, name: '홍길동' }, 2: { id: 2, name: '김철수' } }
// 그룹화
let students = [
{ name: "홍길동", grade: "A" },
{ name: "김철수", grade: "B" },
{ name: "이영희", grade: "A" }
];
let grouped = students.reduce((acc, student) => {
if (!acc[student.grade]) {
acc[student.grade] = [];
}
acc[student.grade].push(student.name);
return acc;
}, {});
console.log(grouped);
// { A: ['홍길동', '이영희'], B: ['김철수'] }
메서드 체이닝
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
// 짝수만 필터 → 제곱 → 합계
let result = numbers
.filter(x => x % 2 === 0) // [2, 4, 6, 8, 10]
.map(x => x * x) // [4, 16, 36, 64, 100]
.reduce((acc, x) => acc + x, 0); // 220
console.log(result); // 220
// 실전 예제: 사용자 데이터 처리
let users = [
{ name: "홍길동", age: 25, active: true },
{ name: "김철수", age: 17, active: false },
{ name: "이영희", age: 30, active: true },
{ name: "박민수", age: 20, active: true }
];
let activeAdultNames = users
.filter(user => user.active && user.age >= 18)
.map(user => user.name)
.sort();
console.log(activeAdultNames);
// ['박민수', '이영희', '홍길동']
6. 실전 예제
예제 1: 배열 유틸리티
// 중복 제거
function unique(arr) {
return [...new Set(arr)];
}
console.log(unique([1, 2, 2, 3, 3, 3])); // [1, 2, 3]
// 배열 청크
function chunk(arr, size) {
const result = [];
for (let i = 0; i < arr.length; i += size) {
result.push(arr.slice(i, i + size));
}
return result;
}
console.log(chunk([1, 2, 3, 4, 5, 6, 7], 3));
// [[1, 2, 3], [4, 5, 6], [7]]
// 배열 차집합
function difference(arr1, arr2) {
return arr1.filter(x => !arr2.includes(x));
}
console.log(difference([1, 2, 3, 4], [2, 4])); // [1, 3]
// 배열 교집합
function intersection(arr1, arr2) {
return arr1.filter(x => arr2.includes(x));
}
console.log(intersection([1, 2, 3, 4], [2, 3, 5])); // [2, 3]
예제 2: 객체 유틸리티
// 객체 깊은 복사
function deepClone(obj) {
if (obj === null || typeof obj !== 'object') {
return obj;
}
if (Array.isArray(obj)) {
return obj.map(item => deepClone(item));
}
const cloned = {};
for (let key in obj) {
cloned[key] = deepClone(obj[key]);
}
return cloned;
}
let original = { a: 1, b: { c: 2 } };
let cloned = deepClone(original);
cloned.b.c = 100;
console.log(original.b.c); // 2 (원본 유지)
console.log(cloned.b.c); // 100
// 객체 병합 (깊은 병합)
function deepMerge(target, source) {
for (let key in source) {
if (source[key] instanceof Object && key in target) {
Object.assign(source[key], deepMerge(target[key], source[key]));
}
}
return Object.assign(target || {}, source);
}
// 객체 필터링
function filterObject(obj, predicate) {
return Object.keys(obj)
.filter(key => predicate(obj[key], key))
.reduce((acc, key) => {
acc[key] = obj[key];
return acc;
}, {});
}
let data = { a: 1, b: 2, c: 3, d: 4 };
let filtered = filterObject(data, value => value > 2);
console.log(filtered); // { c: 3, d: 4 }
예제 3: 데이터 변환
// CSV → 객체 배열
function parseCSV(csv) {
const lines = csv.trim().split("\n");
const headers = lines[0].split(",");
return lines.slice(1).map(line => {
const values = line.split(",");
return headers.reduce((obj, header, i) => {
obj[header] = values[i];
return obj;
}, {});
});
}
const csv = `name,age,city
홍길동,25,서울
김철수,30,부산
이영희,28,서울`;
console.log(parseCSV(csv));
// [
// { name: '홍길동', age: '25', city: '서울' },
// { name: '김철수', age: '30', city: '부산' },
// { name: '이영희', age: '28', city: '서울' }
// ]
// 객체 배열 → CSV
function toCSV(arr) {
if (arr.length === 0) return "";
const headers = Object.keys(arr[0]);
const headerRow = headers.join(",");
const dataRows = arr.map(obj => {
return headers.map(header => obj[header]).join(",");
});
return [headerRow, ...dataRows].join("\n");
}
let users = [
{ name: "홍길동", age: 25 },
{ name: "김철수", age: 30 }
];
console.log(toCSV(users));
// name,age
// 홍길동,25
// 김철수,30
7. 자주 하는 실수와 해결법
실수 1: 배열 복사
// ❌ 참조 복사
let arr1 = [1, 2, 3];
let arr2 = arr1;
arr2[0] = 100;
console.log(arr1); // [100, 2, 3] (원본도 변경!)
// ✅ 얕은 복사
let arr1 = [1, 2, 3];
let arr2 = [...arr1]; // 또는 arr1.slice()
arr2[0] = 100;
console.log(arr1); // [1, 2, 3] (원본 유지)
// ⚠️ 중첩 배열은 얕은 복사
let nested = [[1, 2], [3, 4]];
let copy = [...nested];
copy[0][0] = 100;
console.log(nested); // [[100, 2], [3, 4]] (원본도 변경!)
// ✅ 깊은 복사
let deepCopy = JSON.parse(JSON.stringify(nested));
deepCopy[0][0] = 999;
console.log(nested); // [[100, 2], [3, 4]] (원본 유지)
console.log(deepCopy); // [[999, 2], [3, 4]]
실수 2: sort의 함정
// ❌ 숫자 정렬 (문자열로 비교됨!)
let numbers = [1, 10, 2, 20, 3];
numbers.sort();
console.log(numbers); // [1, 10, 2, 20, 3] (잘못됨!)
// ✅ 비교 함수 사용
numbers.sort((a, b) => a - b);
console.log(numbers); // [1, 2, 3, 10, 20]
실수 3: 객체 비교
// ❌ 객체는 참조 비교
let obj1 = { a: 1 };
let obj2 = { a: 1 };
console.log(obj1 === obj2); // false
// ✅ 깊은 비교 (lodash 사용 또는 직접 구현)
function deepEqual(obj1, obj2) {
if (obj1 === obj2) return true;
if (typeof obj1 !== 'object' || typeof obj2 !== 'object' ||
obj1 === null || obj2 === null) {
return false;
}
const keys1 = Object.keys(obj1);
const keys2 = Object.keys(obj2);
if (keys1.length !== keys2.length) return false;
for (let key of keys1) {
if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) {
return false;
}
}
return true;
}
console.log(deepEqual({ a: 1 }, { a: 1 })); // true
8. 연습 문제
문제 1: 배열 평탄화
중첩된 배열을 1차원 배열로 변환하세요.
function flatten(arr) {
return arr.reduce((acc, item) => {
return acc.concat(Array.isArray(item) ? flatten(item) : item);
}, []);
}
// 테스트
console.log(flatten([1, [2, 3], [4, [5, 6]]]));
// [1, 2, 3, 4, 5, 6]
문제 2: 객체 배열 그룹화
객체 배열을 특정 키로 그룹화하세요.
function groupBy(arr, key) {
return arr.reduce((acc, obj) => {
const groupKey = obj[key];
if (!acc[groupKey]) {
acc[groupKey] = [];
}
acc[groupKey].push(obj);
return acc;
}, {});
}
// 테스트
let users = [
{ name: "홍길동", age: 25, city: "서울" },
{ name: "김철수", age: 30, city: "부산" },
{ name: "이영희", age: 28, city: "서울" }
];
console.log(groupBy(users, "city"));
// {
// 서울: [{ name: '홍길동', ....}, { name: '이영희', ....}],
// 부산: [{ name: '김철수', ....}]
// }
문제 3: 배열 회전
배열을 오른쪽으로 k번 회전하세요.
function rotateArray(arr, k) {
k = k % arr.length;
return [...arr.slice(-k), ...arr.slice(0, -k)];
}
// 테스트
console.log(rotateArray([1, 2, 3, 4, 5], 2));
// [4, 5, 1, 2, 3]
정리
핵심 요약
- 배열 메서드:
- 추가/삭제:
push,pop,shift,unshift,splice - 검색:
indexOf,includes,find,findIndex - 변환:
map,filter,reduce - 정렬:
sort,reverse
- 추가/삭제:
- 객체:
- 생성: 리터럴
{} - 접근:
.또는[] - 메서드:
Object.keys(),Object.values(),Object.entries()
- 생성: 리터럴
- 구조 분해:
- 배열:
let [a, b] = arr - 객체:
let { name, age } = obj
- 배열:
- Spread/Rest:
- Spread: 펼치기
...arr - Rest: 나머지 모으기
...rest
- Spread: 펼치기
- 고차 함수:
map: 변환filter: 필터링reduce: 축약
베스트 프랙티스
- ✅
map/filter/reduce활용 - ✅ 불변성 유지 (원본 변경 최소화)
- ✅ 메서드 체이닝으로 가독성 향상
- ✅ Spread 연산자로 복사
- ✅ 구조 분해로 코드 간결화
다음 단계
- JavaScript 비동기 프로그래밍
- JavaScript 클래스
- JavaScript 모듈
관련 글
심화 부록: 구현·운영 관점
이 부록은 앞선 본문에서 다룬 주제(「JavaScript 배열과 객체 | Array, Object 메서드 완벽 정리」)를 구현·런타임·운영 관점에서 다시 압축합니다. 도메인별 세부 구현은 글마다 다르지만, 입력 검증 → 핵심 연산 → 부작용(I/O·네트워크·동시성) → 관측의 흐름으로 장애를 나누면 원인 추적이 빨라집니다.
내부 동작과 핵심 메커니즘
flowchart TD A[입력·요청·이벤트] --> B[파싱·검증·디코딩] B --> C[핵심 연산·상태 전이] C --> D[부작용: I/O·네트워크·동시성] D --> E[결과·관측·저장]
sequenceDiagram participant C as 클라이언트/호출자 participant B as 경계(런타임·게이트웨이·프로세스) participant D as 의존성(API·DB·큐·파일) C->>B: 요청/이벤트 B->>D: 조회·쓰기·RPC D-->>B: 지연·부분 실패·재시도 가능 B-->>C: 응답 또는 오류(코드·상관 ID)
- 불변 조건(Invariant): 버퍼 경계, 프로토콜 상태, 트랜잭션 격리, FD 상한 등 단계별로 문장으로 적어 두면 디버깅 비용이 줄어듭니다.
- 결정성: 순수 층과 시간·네트워크·스케줄에 의존하는 층을 분리해야 테스트와 장애 분석이 쉬워집니다.
- 경계 비용: 직렬화, 인코딩, syscall 횟수, 락 경합, 할당·GC, 캐시 미스를 의심 목록에 둡니다.
- 백프레셔: 생산자가 소비자보다 빠를 때 버퍼·큐·스트림에서 속도를 줄이는 신호를 어디에 둘지 정의합니다.
프로덕션 운영 패턴
| 영역 | 운영 관점 질문 |
|---|---|
| 관측성 | 요청 단위 상관 ID, 에러율·지연 p95/p99, 의존성 타임아웃·재시도가 대시보드에 보이는가 |
| 안전성 | 입력 검증·권한·비밀·감사 로그가 코드 경로마다 일관적인가 |
| 신뢰성 | 재시도는 멱등 연산에만 적용되는가, 서킷 브레이커·백오프·DLQ가 있는가 |
| 성능 | 캐시·배치 크기·커넥션 풀·인덱스·백프레셔가 데이터 규모에 맞는가 |
| 배포 | 롤백 룬북, 카나리/블루그린, 마이그레이션·피처 플래그가 문서화되어 있는가 |
| 용량 | 피크 트래픽·디스크·FD·스레드 풀 상한을 주기적으로 검증하는가 |
스테이징은 데이터 양·네트워크 RTT·동시성을 프로덕션에 가깝게 맞출수록 재현율이 올라갑니다.
확장 예시: 엔드투엔드 미니 시나리오
앞선 본문 주제(「JavaScript 배열과 객체 | Array, Object 메서드 완벽 정리」)를 배포·운영 흐름에 맞춰 옮긴 체크리스트입니다. 도메인에 맞게 단계 이름만 바꿔 적용할 수 있습니다.
- 입력 계약 고정: 스키마·버전·최대 페이로드·타임아웃·에러 코드를 경계에 둔다.
- 핵심 경로 계측: 요청 ID, 단계별 지연, 외부 호출 결과 코드를 로그·메트릭·트레이스에서 한 흐름으로 본다.
- 실패 주입: 의존성 타임아웃·5xx·부분 데이터·락 대기를 스테이징에서 재현한다.
- 호환·롤백: 설정/마이그레이션/클라이언트 버전을 되돌릴 수 있는지 확인한다.
- 부하 후 검증: 피크 대비 p95/p99, 에러율, 리소스 상한, 알림 임계값을 점검한다.
handle(request):
ctx = newCorrelationId()
validated = validateSchema(request)
authorize(validated, ctx)
result = domainCore(validated)
persistOrEmit(result, idempotentKey)
recordMetrics(ctx, latency, outcome)
return result
문제 해결(Troubleshooting)
| 증상 | 가능 원인 | 조치 |
|---|---|---|
| 간헐적 실패 | 레이스, 타임아웃, 외부 의존성, DNS | 최소 재현 스크립트, 분산 트레이스·로그 상관관계, 재시도·서킷 설정 점검 |
| 성능 저하 | N+1, 동기 I/O, 락 경합, 과도한 직렬화, 캐시 미스 | 프로파일러·APM으로 핫스팟 확인 후 한 가지씩 제거 |
| 메모리 증가 | 캐시 무제한, 구독/리스너 누수, 대용량 버퍼, 커넥션 미반납 | 상한·TTL·힙/FD 스냅샷 비교 |
| 빌드·배포만 실패 | 환경 변수, 권한, 플랫폼 차이, lockfile | CI 로그와 로컬 diff, 런타임·이미지 버전 핀 |
| 설정 불일치 | 프로필·시크릿·기본값, 리전 | 스키마 검증된 설정 단일 소스와 배포 매트릭스 표준화 |
| 데이터 불일치 | 비멱등 재시도, 부분 쓰기, 캐시 무효화 누락 | 멱등 키·아웃박스·트랜잭션 경계 재검토 |
권장 순서: (1) 최소 재현 (2) 최근 변경 범위 축소 (3) 환경·의존성 차이 (4) 관측으로 가설 검증 (5) 수정 후 회귀·부하 테스트.
배포 전에는 git add → git commit → git push 후 npm run deploy 순서를 권장합니다.
자주 묻는 질문 (FAQ)
Q. 이 내용을 실무에서 언제 쓰나요?
A. JavaScript 배열과 객체: Array, Object 메서드 완벽 정리. 배열 (Array)·객체 (Object)로 흐름을 잡고 원리·코드·실무 적용을 한글로 정리합니다. JavaScript·배열·Array 중… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.
Q. 선행으로 읽으면 좋은 글은?
A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. JavaScript 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.
Q. 더 깊이 공부하려면?
A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.
같이 보면 좋은 글 (내부 링크)
이 주제와 연결되는 다른 글입니다.
이 글에서 다루는 키워드 (관련 검색어)
JavaScript, 배열, Array, 객체, Object, map, filter 등으로 검색하시면 이 글이 도움이 됩니다.