모던 JavaScript 튜토리얼을 따라가면서 정리합니다.
4.1. 객체
여덟 개의 자료형 중 일곱 개는 오직 하나의 데이터만 담을 수 있어 원시형(primitive type)이라 부른다.
반면 객체형은 키로 구분된 데이터 집합이나 복잡한 개체(entity)와 같이 다양한 데이터를 저장할 수 있다.
객체는 몇가지 특수한 기능을 가진 연관 배열(associative array)
프로퍼티는 키(key) : 값(value) 쌍으로 이루어져 잇다.
- key엔 문자열이거나 심볼이 허용된다. 보통 문자열이다.
- value엔 모든 자료형이 허용된다.
프로퍼티 키는 프로퍼티 이름 **또는 **식별자라고도 부른다.
객체에선 키를 이용해 프로퍼티를 쉽게 찾을 수 있다.
점 표기법(dot notation)을 이용해 프로퍼티 값을 읽는다.
프로퍼티 삭제:
delete user.age;
프로퍼티 이름이 복수의 단어일 경우 따옴표로 묶어 줘야 한다.
trailing, hanging 쉼표: 마지막 프로퍼티 끝은 쉼표로 끝날 수 있다. => 프로퍼티 추가, 삭제, 이동 용이
상수(const로 선언된) 객체는 수정될 수 있다. const는 객체의 값을 고정하지만, 그 내용은 고정하지 않는다.
빈 객체를 만드는 방법
- 객체 생성자 문법:
let user = new Object()
- 객체 리터럴(object literal)문법:
let user = {}
- 객체 생성자 문법:
대괄호 표기법
- 유효한 변수 식별자
- 공백이 없다.
- 숫자로 시작하지 않는다.
$
,_
를 제외한 특수 문자가 없어야 한다.
키가 유효한 변수 식별자가 아닌 경우 대괄호 표기법(square bracket notation)을 사용해야 한다.
대괄호 표기법 안에서 문자열을 사용할 땐 문자열을 따옴표로 묶어줘야 한다.
대괄호 표기법을 사용할 경우 문자열 뿐만 아니라 모든 표현식의 평가 결과를 프로퍼티로 사용할 수 있다. 다음 코드에서는 변수를 키로 사용하였다.
1 2 3
let key = "like birds"; user[key] = true;
변수 key는 런타임에 평가되기 때문에 사용자 입력값 변경 등에 따라 값이 변경될 수 있다. 어떤 경우든, 평가가 끝난 이후의 결과가 프로퍼티 키로 사용된다. 이를 응용하면 코드를 유연하게 작성할 수 있다. 점 표기법은 이런 방식이 불가능하다.
계산된 프로퍼티(computed property)
객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우, 이를 계산된 프로퍼티(computed property)라고 부른다.
1 2 3 4 5 6 7
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple"); let bag = { [fruit] = 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아온다. }; alert(bag.apple); // fruit에 apple이 할당되었다면, 5가 출력된다.
아래 예시는 위 예시와 동일하게 동작한다.
1 2 3 4 5 6
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple"); let bag = {}; // 변수 fruit을 사용해 프로퍼티 이름을 만든다. bag.fruit = 5;
대괄호 안에는 복잡한 표현식이 올 수 있다.
1 2 3 4
let fruit = 'apple'; let bag = { [fruit + 'Computers']: 5 // bag.appleComputers = 5 };
대괄호 표기법은 프로퍼티 이름과 값의 제약을 없애주기 때문에 점 표기법보다 강력하다. 그러나 작성하기 번거롭다.
프로퍼티 이름이 확정된 상황이고, 단순한 이름이라면 점 표기법을 사용하다가 복잡한 상황이 발생했을 때 대괄호 표기법으로 바꾸는 경우가 많다.
단축 프로퍼티
실무에서는 프로퍼티 값을 기존 변수에서 받아와 사용하는 경우가 종종 있다. 이 경우 프로퍼티 값 단축 구문(property value shorthand)를 사용하면 변수를 사용해 프로퍼티를 쉽게 만들 수 있다.
사용 전
1 2 3 4 5 6 7 8 9 10
function makeUser(name, age) { return { name: name, age: age, // ...등등 }; } let user = makeUser("John", 30); alert(user.name); // John
사용 후
1 2 3 4 5 6 7
function makeUser(name, age) { return { name, // name: name 과 같음 age, // age: age 와 같음 // ... }; }
프로퍼티 이름의 제약사항
예약어를 객체 프로퍼티 키로 사용해도 된다.
1 2 3 4 5 6 7
let obj = { for: 1, let: 2, return: 3 }; alert( obj.for + obj.let + obj.return ); // 6
프로퍼티 이름엔 특별한 제약이 없다. 어떤 문자형, 심볼형 값도 프로퍼티 키가 될 수 있다.
문자형이나 심볼형에 속하지 않은 값은 문자열로 자동 형 변환된다.
__proto__
의 경우 역사적인 이유 때문에 특별 대우를 받는다.1 2 3
let obj = {}; obj.__proto__ = 5; // 숫자를 할당한다. alert(obj.__proto__); // [object Object] - 숫자를 할당했지만 값은 객체가 되었다. 의도한대로 동작하지 않는다.
in
연산자로 프로퍼티의 존재 여부 확인하기
존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고
undefined
를 반환한다. (null을 반환하는 자바와 다르다.) 따라서 일치연산자를 사용해undefined
과 프로퍼티 이름을 비교하여 프로퍼티 존재 여부를 확인할 수 있다.그러나 프로퍼티는 존재하는데 값에
undefined
를 할당한 경우 프로퍼티 존재 여부를 제대로 판단할 수 없다. 이 경우 프로퍼티는 존재하지만 판단 결과는 false가 되기 때문이다.이 외에도 연산자
in
을 사용하면 프로퍼티 존재 여부를 확인할 수 있다."key" in object
1 2 3 4 5 6 7
let obj = { test: undefined }; alert( obj.test ); // 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력된다. 그런데 프로퍼티 test는 존재한다. alert( "test" in obj ); // `in`을 사용하면 프로퍼티 유무를 제대로 확인할 수 있다(true가 출력됨).
for...in
반복문
for...in
반복문을 사용하면 객체의 모든 키를 순회할 수 있다.문법
1 2 3
for (key in object) { // 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행한다. }
반복 변수 명은 자유롭게 정할 수 있다.
객체 정렬 방식
객체는 특별한 방식으로 정렬된다. 정수 프로퍼티(integer property)는 자동으로 정렬되고, 그 외의 프로퍼티는 객체에 추가한 순서 그대로 정렬된다.
1 2 3 4 5 6 7 8 9 10 11
let codes = { "49": "독일", "41": "스위스", "44": "영국", // .., "1": "미국" }; for (let code in codes) { alert(code); // 1, 41, 44, 49 }
정수 프로퍼티: 변형 없이 정수에서 왔다 갔다 할 수 있는 문자열
위 예시에서 객체에 추가한 순서대로 정렬하기 위해서는 각 나라 번호가 정수로 취급되지 않도록 각 나라 번호 앞에
"+"
를 붙이면 된다.
자바스크립트에는 일반 객체 외에도 다양한 종류의 객체가 있다.
Array
: 정렬된 데이터 컬렉션을 저장할 때 쓰인다.Date
: 날짜와 시간 정보를 저장할 때 쓰인다.Error
: 에러 정보를 저장할 때 쓰인다.
Array와 Date은 객체형에 속한다. 객체에 다양한 기능을 넣어 확장한 또 다른 객체이다.
과제
객체야 안녕?
1
2
3
4
5
let user = {};
user.name = "John";
user.surname = "Smith";
user.name = "Pete";
delete user.name;
객체가 비어있는지 확인하기
1
2
3
4
5
6
7
let schedule = {};
alert( isEmpty(schedule) ); // true
schedule["8:30"] = "get up";
alert( isEmpty(schedule) ); // false
1
2
3
4
5
6
function isEmpty(obj) {
for (let key in obj) {
return false;
}
return true;
}
프로퍼티 합계 구하기
1
2
3
4
5
6
7
8
9
10
11
12
13
let salaries = {
John: 100,
Ann: 160,
Pete: 130
}
let sum = 0;
for (let key in salaries) {
sum += salaries[key];
}
alert(sum);
프로퍼티 값 두 배로 부풀리기
1
2
3
4
5
6
7
function multiplyNumeric(obj) {
for (let key in obj) {
if (typeof obj[key] === "number") {
obj[key] *= 2;
}
}
}