WeniVooks

검색

JavaScript 베이스캠프

객체타입과 배열

1. 객체타입 (Object Types)

1.1 객체타입의 특징

원시 타입과 달리 객체 타입은 값을 변경할 수 있습니다. 아래 예제를 실행해보고 주석을 해제하고 한 번 더 실행해보세요.

let arr = [1, 2, 3]; arr[0] = 100 console.log(arr); // let str = 'hello'; // str[0] = 'H'; // console.log(str);

2. 배열 (Array)

배열은 데이터를 순서대로 저장하는 객체입니다. 하나의 데이터를 표현하는 원시타입과 달리 여러 개의 데이터를 한 변수에 저장할 수 있기 때문에 데이터를 추가하거나 제거, 정렬, 검색 등 다양한 작업을 수행할 수 있습니다.

2.1. 배열의 특징
2.1.1. 배열 생성

배열은 빈 배열로 생성하거나 요소가 포함된 배열로 생성할 수 있습니다. 배열은 대괄호([])를 사용하여 생성하며, 배열 안에 요소를 쉼표(,)로 구분하여 나열합니다. 배열은 다양한 타입의 데이터를 포함할 수 있습니다. 또한 배열은 const로 선언하는 것이 일반적입니다. 그 이유는 const로 선언한 것이 '배열의 요소를 바꿀 수 없어'가 아니라 '배열의 주소값을 바꿀 수 없어'이기 때문입니다. 아래 예제에서는 arr2가 [1, 2, 3]을 가리키고 있다는 사실을 변경시키지 않겠다는 의미입니다.

const arr1 = []; const arr2 = [1, 2, 3]; const arr3 = new Array(4, 5, 6); const arr4 = new Array(3); console.log(arr1) console.log(arr2) console.log(arr3) console.log(arr4)
2.1.2. 배열 요소 접근

배열은 숫자를 사용하여 값에 접근할 수 있습니다. 숫자는 값의 순서를 의미하며, 이 순서를 인덱스(index)라고 부르고 배열 안에 존재하는 값을 원소(elements)라고 부릅니다.

const arr = [10, 20, 30]; // 배열 안의 원소에 접근하기 위해서는 인덱스 번호를 이용합니다. console.log(arr[0]); // 10 console.log(arr[1]); // 20 console.log(arr[2]); // 30 console.log(arr[3]); // ??
2.1.3. 배열의 길이

배열은 길이를 나타내는 length 프로퍼티를 가지고 있습니다. 문자열에서도 사용했던 length 프로퍼티와 같은 역할을 합니다.

const arr = [10, 20, 30, 40, 50]; console.log(arr.length); // 5
2.1.4. 다차원 배열

배열은 배열 안에 다른 배열을 포함할 수 있습니다. 이러한 배열을 다차원 배열이라고 합니다.

const arr = [ [1, 2], [3, 4], [5, 6], ]; console.log(arr[0][0]); console.log(arr[2][1]);

2차원 배열은 행렬이라고 불리며, 3차원 이상의 배열도 만들 수 있습니다.

const arr = [ [ [1, 2], [3, 4], ], [ [5, 6], [7, 8], ], ]; console.log(arr[0][1][0]); console.log(arr[1][0][1]);
2.2. 배열의 메소드

배열의 메소드는 배열을 다루는데 유용한 메소드들입니다. 배열의 메소드는 배열의 요소를 추가하거나 제거, 정렬, 검색 등 다양한 작업을 수행할 수 있습니다. 여기서는 실무에서 주로 사용되는 배열의 메소드를 알아보겠습니다.

2.2.1. push()와 pop()

push() 메소드는 배열의 끝에 요소를 추가하고 길이를 반환합니다. pop() 메소드는 배열의 마지막 요소를 꺼내어 반환합니다. 꺼낸 요소는 배열에서 제외됩니다.

const arr = [1, 2, 3]; arr.push(4); console.log(arr); // [1, 2, 3, 4] arr.pop(); console.log(arr); // [1, 2, 3]

여기서 pop() 메소드는 배열의 마지막 요소를 꺼내어 반환하는데 이때 꺼낸 요소를 아래와 같이 활용하기도 합니다.

const arr = [1, 2, 3]; const last = arr.pop(); console.log(last); // 3
2.2.2. shift()와 unshift()

shift() 메소드는 배열에서 첫 번째 요소를 꺼내어 반환합니다. unshift() 메소드는 배열의 첫 번째 요소로 새로운 요소를 추가합니다.

const arr = ['사과', '바나나', '수박']; arr.shift(); console.log(arr); arr.unshift('오이', '배'); console.log(arr);
2.2.3. slice()

slice() 메소드는 배열에서 요소들을 추출하여 새로운 배열로 반환합니다. 첫 번째 인자는 추출을 시작할 인덱스입니다. 두 번째 인자는 추출을 끝낼 인덱스입니다. 추출할 요소는 첫 번째 인자에서 시작하여, 두 번째 인자에서 바로 이전 요소까지입니다. 두 번째 인자는 생략 가능하며, 생략하거나 배열의 길이보다 큰 값을 전달하면 배열의 끝까지 추출합니다.

const arr = ['apple', 'banana', 'cherry', 'durian', 'elderberry']; console.log(arr.slice(1, 4)); // 2번째부터 4번째 요소까지 추출 console.log(arr.slice(2)); // 3번째 요소부터 끝까지 추출 console.log(arr.slice()); // 배열 전체를 추출 console.log(arr.slice(0, 10)); // 배열 전체를 추출
2.2.4. sort()

sort() 메소드는 배열의 요소를 정렬하는데 사용됩니다. 메소드를 호출하면 배열을 변경하며, 정렬된 배열을 반환합니다.

const avengers = ['아이언맨', '스파이더맨', '헐크', '토르']; console.log(avengers.sort());

숫자를 정렬하려고 하면 의도와는 다르게 정렬될 수 있습니다.

const nums = [3, 1, 8, 6]; console.log(nums.sort()); const nums2 = [23, 5, 1000, 42]; console.log(nums2.sort());

숫자를 정렬하려고 하면 의도와는 다르게 정렬이 되는 이유는 정렬하기 전 원소를 문자열로 전환한 후에 유니코드 포인트의 순서대로 변환하기 때문입니다. 포인트는 문자에 부여한 고유한 16진수 숫자값입니다.

숫자형 데이터 정렬의 이러한 단점을 해결하기 위해 비교 함수(compareFunction)를 사용할 수 있습니다. 비교 함수가 제공되면 원소의 순서는 비교 함수의 반환 값에 따라 정렬됩니다.

비교 함수의 두 인자 a, b를 비교해서(즉, 빼서) 0보다 작은 수 즉, 음수가 나오면 a를 앞으로 위치하고, 두 인자를 뺐는데 0보다 큰 양수가 나오면  b를 앞으로 위치합니다. 0이 나오면 위치를 변경하지 않습니다.

정상 작동되는 코드로 살펴보겠습니다.

let numbers = [4, 2, 5, 1, 3]; numbers.sort((a, b) => a - b); console.log(numbers);
2.2.5. forEach()

forEach() 메소드는 배열의 각 요소에 대해 주어진 함수를 실행합니다. 이 때, 함수는 인자로 배열 요소, 인덱스를 받습니다. forEach() 메소드는 배열의 요소를 순환하면서 해당 요소를 함수로 전달하고, 이 함수가 각 요소에 대해 실행됩니다.

const 배열 = ['a', 'b', 'c'];
배열.forEach(요소마다_실행시킬_함수);
const 배열 = ['a', 'b', 'c'];
배열.forEach(요소마다_실행시킬_함수);

형태는 위와 같은 형태가 됩니다. 좀 더 이해하기 쉬운 예제를 살펴보겠습니다.

const arr = ['참외', '키위', '감귤']; function 함수(요소, 인덱스) { console.log(요소, 인덱스); } arr.forEach(함수);

다만 위와 같이 함수를 따로 선언하지 않고, 아래와 같이 함수를 forEach() 안에서 선언할 수도 있습니다.

const arr = ['참외', '키위', '감귤']; arr.forEach(function (item, index) { console.log(item, index); });

요즘은 화살표 함수를 좀 더 많이 사용합니다.

const arr = ['참외', '키위', '감귤']; arr.forEach((item, index) => { console.log(item, index); });

forEach() 메소드는 배열의 각 요소에 대해 특정 작업을 수행할 때 사용됩니다. 예를 들어, 배열의 각 요소를 이용하여 다른 배열을 만들거나, 요소를 삭제하거나, 값을 변경하는 등의 작업을 수행할 수 있습니다.

const avengers = ['spiderman', 'ironman', 'hulk', 'thor']; const newAvengers = []; avengers.forEach(item => { newAvengers.push('💖' + item + '💖'); }); console.log(avengers);
2.2.6. map()

map() 메소드는 배열의 각 요소에 대해 주어진 함수를 실행하고, 그 결과를 새로운 배열로 반환합니다.

const arr = [1, 2, 3]; const newArr = arr.map(function (item, index) { return item * index; }); console.log(newArr);

map() 메소드의 첫 번째 인자로는 배열의 각 요소를 처리할 함수를, 두번째는 요소의 인덱스를 전달합니다. 이 함수는 배열의 각 요소를 매개변수로 받아 처리한 후, 그 결과를 반환합니다.

forEach() 메소드와 비슷해 보이지만, map() 메소드는 새로운 배열을 반환하는 것이 다릅니다. forEach() 메소드는 배열의 요소를 순회 돌고 싶을 때, map() 메소드는 return되는 값으로 새로운 배열을 만들 때 사용합니다.

아래처럼 배열 안에 객체에서 데이터를 뽑는 형태로도 사용합니다.

const data = [ { _id: '642ba3980785cecff3f39a8d', index: 0, age: 28, eyeColor: 'green', name: 'Annette Middleton', gender: 'female', company: 'KINETICA', }, { _id: '642ba398d0fed6e17f2f50c9', index: 1, age: 37, eyeColor: 'green', name: 'Kidd Roman', gender: 'male', company: 'AUSTECH', }, { _id: '642ba39827d809511d00dd8d', index: 2, age: 39, eyeColor: 'brown', name: 'Best Ratliff', gender: 'male', company: 'PRISMATIC', }, ]; // const ages = data.map(item => item.age); const ages = data.map((item) => item['age']); console.log(ages);
2.2.7. includes()

includes() 메소드는 배열에 특정 요소가 포함되어 있는지를 확인하여, 포함되어 있으면 true, 그렇지 않으면 false를 반환합니다. 이 메소드는 배열에서 특정 값을 찾을 때 유용합니다.

const arr1 = ['hello', 'world', 'hojun']; console.log(arr1.includes('world')); // true - 'world'가 배열에 포함됨 const arr2 = ['hello', 'world', 'hojun']; console.log(arr2.includes('leehojun')); // false - 'leehojun'이 배열에 포함되지 않음 const arr3 = ['hello', 'world', 'hojun']; console.log(arr3.includes('jun')); // false - 'jun'이 배열에 포함되지 않음

includes() 메소드는 대소문자를 구분하여 검색합니다. 예를 들어, 'World'와 'world'는 다른 문자열로 인식됩니다.

const arr4 = ['hello', 'world', 'hojun']; console.log(arr4.includes('World')); // false - 대소문자 구분
2.2.8. join()

join() 메소드는 배열의 모든 요소를 연결하여 하나의 문자열로 만듭니다. 이 메소드는 배열의 각 요소를 연결할 때 사용할 문자열을 인자로 받습니다. 인자를 생략하면 쉼표(,)로 연결됩니다.

const arr1 = ['hello', 'world', 'hojun']; console.log(arr1.join('!')); // "hello!world!hojun" const arr2 = ['010', '1034', '1100']; console.log(arr2.join('-')); // "010-1034-1100" const arr3 = ['apple', 'banana', 'cherry']; console.log(arr3.join()); // "apple,banana,cherry" - 기본 구분자인 쉼표(,)로 연결

join() 메소드를 사용할 때 주의할 점은 숫자를 문자열로 연결할 때 0으로 시작하는 숫자는 다른 진수로 해석될 수 있다는 것입니다. 예를 들어, 010은 8진수로 해석됩니다. 해당 예제는 위니북스에서는 허락하지 않는 연산이니 콘솔에서 확인해주세요.

위니북스에서 실행되지 않는 이유는 위니북스에서는 보다 엄격한 연산을 하기 때문입니다. SyntaxError: Octal literals are not allowed in strict mode. 에러가 발생하며 엄격모드와 같은 실행환경을 제공합니다. 엄격모드는 자바스크립트의 문법을 보다 엄격하게 적용하여 오류를 줄이는 역할을 합니다. 다만 일반적인 자바스크립트는 이러한 오류를 발생시키지 않습니다.

const arr = [010, 1034, 1100];
console.log(arr.join('-')); // "8-1034-1100" - 010은 8진수로 해석됨
 
// 0b100는 바이너리(2진수), 0o100는 옥타(8진수), 0x100는 헥사(16진수)를 표현합니다.
console.log(0b100); // 4 (2진수 100은 10진수로 4)
console.log(0o100); // 64 (8진수 100은 10진수로 64)
console.log(0x100); // 256 (16진수 100은 10진수로 256)
const arr = [010, 1034, 1100];
console.log(arr.join('-')); // "8-1034-1100" - 010은 8진수로 해석됨
 
// 0b100는 바이너리(2진수), 0o100는 옥타(8진수), 0x100는 헥사(16진수)를 표현합니다.
console.log(0b100); // 4 (2진수 100은 10진수로 4)
console.log(0o100); // 64 (8진수 100은 10진수로 64)
console.log(0x100); // 256 (16진수 100은 10진수로 256)

이러한 점을 유의하면서 join() 메소드를 사용하면 배열을 쉽게 문자열로 변환할 수 있습니다.

4장 객체 타입에 관하여4.2 객체