이 글은 저서 [인사이드 자바스크립트]를 공부하고자 작성되었으며, 핵심 개념과 새롭게 알게 된 내용을 위주로 기록하였습니다.
이 장에서 다루는 내용
배열은 js 객체의 특별한 형태다.
- c와 자바와 달리, 굳이 크기를 지정하지 않아도 되며,
- 어느 위치에 어느 타입의 데이터를 저장해도 에러가 생기지 않는다
배열 리터럴이란, js에서 새로운 배열을 만드는데 사용하는 표기법이다.
배열 리터럴은 대괄호 [ ] 를 사용한다.
var colorArr = ['hello','hi'];
console.log(colorArr[1])
배열도 동적으로 배열 원소를 추가할 수 있다.
특히 js는 배열 원소 값을 순차적으로 넣을 필요 없이 아무 인덱스 위치에나 값을 동적으로 추가할 수 있다.
var emptyArr = []; // 빈 배열 생성
console.log(emptyArr[0]) // undefinded
emptyArr[0] = 1;
emptyArr[3] = 2;
console.log(emptyArr) // [1, undefined * 2, 2]
console.log(emptyArr.length); // 4
js는 배열의 크기를 현재 배열의 인덱스 중 가장 큰 값을 기준으로 정한다.
위 예제에서도 가장 큰 인덱스가 3이므로, 0부터 3까지 총 4개인 것이다.
js의 모든 배열은 length 프로퍼티가 있다. length 프로퍼티는 배열의 원소 개수를 나타내지만, 실제로 배열에 존재하는 원소 개수과 일치하는 것은 아니다.
즉, lenght 프로퍼티는 배열 내에 가장 큰 인덱스에 1을 더한 값이다.
배열 리터럴로 생성한 arr은 최초에는 빈 배열이다. length 프로퍼티의 값도 0이다. arr[100]에 원소 값을 저장하면, length 프로퍼티는 101이 된다.
하지만 실제 메모리는 length 크기처럼 할당되지는 않는다.
length 프로퍼티는 코드를 통해 명시적으로 변경할 수 있다.
var arr = [0,1,2];
arr.length = 5;
console.log(arr) // [0,1,2,undefined * 5]
arr.length = 2;
console.log(arr) // [0,1]
js는 배열에 사용 가능한 다양한 표준 메서드를 제공한다.
이런 배열 메서드는 length 프로퍼티를 기반으로 동작한다.
예시
var arr = [0,1,2];
arr.length = 4;
console.log(arr) // [0,1,2,undefined]
arr.push(3)
console.log(arr) // [0,1,2,undefined ,3]
js에선 배열도 객체다. 하지만 일반 객체와는 차이가 있다.
var arr = ['one','two','three'];
var obj = {
'0' : 'one',
'1' : 'two',
'2' : 'three',
}
console.log(obj[0]); // one
console.log(typeof arr) // Object
console.log(typeof obj) // Object
console.log(arr.length) // 3
console.log(obj.length) // undefined
arr.push('four')
obj.push('four') // 오류 !!
배열과 객체 모두 typeof 연산 결과 object가 출력된다.
객체는 배열 표준 메서드를 사용할 수 없다.
- 배열과 객체가 자신의 부모인 프로토타입 객체가 서로 다르기 때문이다.
배열은 Array.protorype에 포함된 메서드와 Object.prototype에 정의된 메서드를 모두 사용할 수 있다.
배열의 프로토타입
객체의 프로토타입
-> 이미지 출처
var arr = [1,2,3];
arr.color = 'red';
console.log(arr.length) // 3
배열에 동적으로 프로퍼티를 추가해도, length 프로퍼티 값은 변하기 않는다.
배열의 lenght 프로퍼티는 배열 원소의 가장 큰 인덱스가 변했을 경우만 변경된다.
결국 배열도 객체처럼 'key : value'의 형태로 배열 원소 및 프로퍼티 등이 있는 것을 알 수 있다.
for ( var prop in arr) {
console.log(prop, arr[prop]);
}
for (var i=0; i<arr.length; i++) {
console.log(i, arr[i]);
}
delete 연산자로 배열의 특정 요소를 삭제해도, 배열의 length 값은 변하지 않는다.
- delete는 해당 요소의 값을 undefined로 변경할 뿐, 원소 자체를 삭제하지 못하지 때문이다.
- 원소 자체를 완전히 삭제하려면 splice() 배열 메서드를 사용해야한다.
var arr = [1,2,3];
delete arr[0];
console.log(arr, arr.length);
arr.splice(0,1);
console.log(arr,arr.length);
배열은 일반적으로 배열 리터털로 생성하지만, 이것도 결국 js 기본 제공 Array() 생성자 함수로 배열을 생성하는 과정을 단순화시킨 것이다.
일부 js 개발자들은 Array() 생성자 함수로 배열을 생성하는 코드를 작성하기도 하므로 간단히 알아두기만 하면 좋다.
생성자 함수로 객체를 생성할 때는 반드시 new 연산자를 같이 써야한다.
호출 인자 수에 따라 동작이 다르므로 주의해야한다.
- 인자가 1개이고, 숫자일 경우 : 호출 인자를 lenght로 같은 빈배열 생성
- 그 외 : 호출된 인자를 요소로 같은 배열 생성
length 프로퍼티를 가진 객체를 "유사 배열 객체"라 한다.
유사 배열 객체는 js의 표준 배열 메서드를 사용하는게 가능하다.
var arr = ['foo'];
var obj = {
name : 'foo',
length : 1
};
arr.push('hello');
console.log(arr); // ['foo','hello']
obj.push('hello'); // error !!
위 예제에서 obj는 유사 배열 객체지, 배열은 아니므로 바로 push 함수를 호출할 경우 에러가 발생한다.
하지만 4장에서 배울 apply() 메서드를 사용하면 객체지만 표준 배열 메서드를 활용할 수 있다.
(자세한 것은 4.4.2.4 call과 apply 메서드를 이용한 명시적인 this 바인딩에서 자세히 알아보자 ->)
var obj = {
name : 'foo',
length : 1
};
Array.prototype.push.apply(obj, ['baz']);
console.log(obj) // ['1':'baz', name : 'foo',
length : 2]