본문 바로가기
Computer Science/Javascript

JavaScript - 데이터 타입과 연산자(프로토타입/배열)

by 마늘아빠 2021. 4. 15.
728x90
반응형
프로토타입

자바스크립트의 모든 객체는 자신의 부모 역할을 하는 객체와 연결되어 있다. 그리고 이것은 마치 객체지향의 상속 개념과 같이 부모 객체의 프로퍼티를 마치 자신의 것처럼 쓸 수 있는 것 같은 특징이 있다. 이러한 부모 객체프로토타입 객체라고 한다.


var foo = {
     name: 'foo',
     age: 30,
};
console.log(foo.toString());
console.dir(foo);

출력 결과

foo에는 toString()이라는 메서드가 없음에도 Object라고 출력이 되는 것을 확인할 수 있는데, 이는 foo 객체가 아닌 프로토타입 객체가 toString() 메서드를 가지고 있다는 것을 뜻한다.

__proto__란 해당 객체의 프로토타입 객체를 뜻한다. 그리고 여기에 toString() 메서드가 있는 것을 확인할 수 있다.


모든 객체의 프로토타입은 자바스크립트의 룰에 따라 객체를 생성할 때 결정된다. 위와 같이 리터럴 방식으로 생성 된 객체의 경우에는 Object.prototype 객체가 프로토타입 객체가 된다. 그리고 놀랍게도 이러한 프로토타입의 객체를 동적으로 변경이 가능하다. 이러한 특징을 이용해서 객체 상속 등의 기능을 구현 할 수 있다.

 

배열

자바스크립트에서 배열은 객체의 특별한 형태다. 굳이 길이를 지정하지 않아도 되고, 어떤 위치에 어느 타입의 데이터를 저장하더라도 에러가 발생하지 않는다.

배열 리터럴

배열 리터럴은 자바스크립트에서 새로운 배열을 만드는 데 사용하는 표기법이다. 객체 리터럴이 중괄호( { } )를 이용한 표기법이라면 배열 리터럴은 대괄호( [ ] )를 이용한다.


// 배열 리터럴을 통한 5개 원소를 가진 배열 생성
var colorArr = ['orange', 'yellow', 'blue', 'green', 'red'];

console.log(colorArr[0]);
console.log(colorArr[1]);
console.log(colorArr[2]);
console.log(colorArr[3]);
console.log(colorArr[4]);

출력 결과

위와 같이 배열리터럴은 각 요소의 값만을 포함한다. 객체가 프로퍼티의 이름으로 대괄호나 마침표 표기법을 이용해 해당 프로퍼티에 접근했다면, 배열의 경우에는 배열 내 위치 인덱스 값을 넣어서 접근한다.

배열의 위치 인덱스는 0부터 시작한다.


 

배열의 요소 생성

객체가 동적으로 프로퍼티를 추가할 수 있듯, 배열도 동적으로 배열 원소를 추가할 수 있다. 순차적으로 넣을 필요도 없이 원하는 아무 인덱스 위치에나 값을 동적으로 추가할 수 있다.


// 빈 배열
var emptyArr = [];
console.log(emptyArr[0]); // undefined

// 배열 요소 동적 생성
emptyArr[0] = 100;
emptyArr[3] = true;
emptyArr[7] = 'seven';
console.log(emptyArr); // undefined와 섞여서 나온다.
console.log(emptyArr.length); // 길이 8

출력 결과


 

배열의 length 프로퍼티

배열의 length 프로퍼티는 배열 내 가장 큰 인덱스 +1 한 값이다. 하지만 length는 명시적으로 값을 변경할 수도 있다. 길이가 더 길어진다면 length 값은 변하지만, undefined로 실제 메모리가 할당 되지는 않는다.

반대로 길이를 줄인다면 length 프로퍼티를 벗어나게 되고, 이때 실제 값은 삭제된다.

 

배열과 객체

배열 역시 객체다. 하지만 일반적인 객체와는 차이가 있다. 하지만 일반적인 객체와 비교해보면 프로토타입 객체가 다르다. 일반 객체 표준 메서드를 리터럴 방식으로 생성하면 Object.prototype 객체가 부모다. 반면, 배열의 경우에는 Array.prototype 객체가 부모가 된다. 이로 인해, 해당 객체가 사용할 수 있는 메서드의 차이가 생긴다. 

prototype의 차이

 

배열의 프로퍼티 동적 생성

배열도 자바스크립트의 객체이므로 인덱스가 숫자인 배열 원소 이외에도 객체처럼 동적으로 프로퍼티를 추가할 수 있다.


// 배열 생성
var arr = ['zero', 'one', 'two'];
console.log(arr.length); // 3

// 프로퍼티 동적 추가
arr.color = 'blue';
arr.name = 'array';
console.log(arr.length); // 역시나 3

// 배열의 원소 추가
arr[3] = 'red';
console.log(arr.length); // 4

// 배열 객체 출력
console.dir(arr);

출력 결과

배열에 동적으로 프로퍼티를 추가하면 length에는 변화가 없다.

arr[3] 처럼 가장 큰 인덱스에 변화가 생긴 경우에만 length가 변했음을 유의하자.

또한, 배열내부에는 key:value 형태로 원소 및 프로퍼티가 있음을 확인할 수 있다.


배열의 프로퍼티 열거

for문과 for in 문으로 열거가 가능하다. 하지만 for in문을 이용하면 불필요한 프로퍼티까지 나올 수 있으므로 for문을 이용하는것이 일반적이다.


// 배열 생성
var arr = ['zero', 'one', 'two'];

// 프로퍼티 동적 추가
arr.color = 'blue';
arr.name = 'array';

// 배열의 원소 추가
arr[3] = 'red';

console.log('for in');
for (let prop in arr) {
     console.log(prop, arr[prop]);
}

console.log('for');
for (let i = 0; i < arr.length; i++) {
     console.log(i, arr[i]);
}

출력 결과

for in문에서 key:value까지 나오는 반면 for문에서는 배열의 요소만을 출력하는 것을 볼 수 있다.


배열 요소 삭제

배열의 요소를 삭제할 때, delete로 지울수도 있다. 하지만 이 경우 배열의 length가 변하지 않고 해당 위치에 undefined가 할당된다. 즉 원소 자체가 삭제되는 것은 아니다.

때문에 일반적으로 배열을 삭제할 때, splice() 메서드를 이용한다.

 splice() 배열 메서드
 splice( start, deleteCount, item... )
 
 start - 배열의 시작 위치
 deleteCount - start에서 지정한 시작 위치부터 삭제할 요소의 수
 item - 삭제할 위치에 추가할 요소

var arr = ['zero', 'one', 'two', 'three'];

arr.splice(2, 1);
console.log(arr.length);
console.log(arr);

출력결과

2번 위치부터 1개의 요소가 삭제되었음을 확인할 수 있다.


유사 배열 객체

객체가 배열처럼 length 프로퍼티를 가지고 있다면 어떻게 될까? 이를 유사배열객체 ( array-like object) 라고 한다!


var arr = ['baz'];
var obj = {
     name: 'foo',
     length: 1,
};

arr.push('baz');
console.log(arr);

obj.push('baz'); // 에러

당연하게도 obj는 push메서드가 없으므로 에러가 발생한다!

하지만 apply()메서드를 이용하면 객체도 배열 메서드를 이용하는 것이 가능해진다.

var arr = ['baz'];
var obj = {
     name: 'foo',
     length: 1,
};

arr.push('baz');
console.log(arr);

Array.prototype.push.apply(obj, ['baz']);
console.log(obj);

출력결과

이렇게 length도 +1 되고, push() 메서드도 정상 작동 한 것을 확인 할 수 있다.

apply() 메서드는 나중에 다시 자세히 알아보도록 하자!


 

반응형