객체
객체혀 자료형은 원시형과는 달리 다양한 데이터를 담을 수 있다. 키로 구분된 데이터 집합이나 복잡한 개체를 저장할 수 도 있다.
객체 작성
객체는 중괄호를 통해서 만들 수 있고 ‘키(key) : 값(value)’ 쌍으로 구성 된 프로퍼티를 여러개 넣을 수 있는데 key에는 문자형, value에는 거의 모든 자료형이 허용된다. 프로퍼티 키는 ‘프로퍼티 이름’ 이라고도 부른다.
빈 객체를 만드는 방법은 두가지가 있다.
let user = new Object() // 객체 생성자 문법
let user = {}; // 객체 리터럴 문법, 주로 사용
리터럴과 프로퍼티
중괄호 안에는 ‘키:값’ 쌍으로 구성된 프로퍼티가 들어간다.
let user = { // 객체
name: "John", // 키: "name", 값: "John"
age: 30 // 키: "age", 값: 30
};
프로퍼티 값 얻기
user.name // "John"
user.age // 30
프로퍼티 값 추가
user.isAdmin = true;
프로퍼티 삭제
delete user.age;
key에 여러 단어를 조합한 경우
let user = {
name: "John",
age: 30,
"likes birds": true // 복수의 단어는 따옴표로 묶어야 합니다.
};
대괄호 표기법
여러 단어를 조합해 프로퍼티 키를 만든 경우엔, 점 표기법을 사용해 프로퍼티 값을 읽을 수 없다. 이럴 경우에는 대괄호 표기법을 사용하자
let user = {};
// set
user["likes birds"] = true;
// get
alert(user["likes birds"]); // true
// delete
delete user["likes birds"];
대괄호 표기법을 사용하면 아래 예시에서 변수를 키로 사용한 것과 같이 문자열 뿐만 아니라 모든 표현식의 평가 결과를 프로퍼티 키로 사용할 수 있다.
let key = "likes birds";
// user["likes birds"] = true; 와 같습니다.
user[key] = true;
변수 key는 런타임에 평가되기 때문에 값이 변경될 수 있다. 어떤 경우든, 평가가 끝난 이후의 결과가 프로프로퍼티 키로 사용된다. 이를 응용하면 유연하게 작성할 수 있다.
let user = {
name = "John",
age : 30
};
let key = prompt("사용자의 어떤 정보를 얻고 싶으신가요?", "name");
// 변수로 접근
alert(user[key]); // John (프롬프트 창에 "name"을 입력한 경우)
점 표기법은 이런 방식이 불가능하다.
let user = {
name: "John",
age: 30
};
let key = "name";
alert( user.key ) // undefinded
계산된 프로퍼티
객체를 만들 때 리터럴 안의 프로퍼티 키가 대괄호로 둘러쌓이 있는 경우, 이를 계산된 프로퍼티 라고 부른다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit] : 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아온다.
}
alert( bag.apple ); // // fruit에 "apple"이 할당되었다면, 5가 출력됩니다.
위 예시에서 [fruit]는 프로퍼티 이름을 변수 fruit에서 가져오겠다는 것을 의미한다. 사용자가 프롬프트 대화상자에 apple을 입력했다면 bag에는 {apple : 5}가 할당되었을 것이다.
아래 예시는 위 예시와 동일하게 작동한다.
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {};
// 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
bag[fruit] = 5;
다음 예시처럼 대괄호 안에 복잡한 표현식이 올 수도 있다.
let fruit = 'apple',
let bag = {
[fruit + 'Computers']: 5 // bag.appleComputers = 5
}
결론
대괄호 표기법은 이름과 값의 제약을 없애주기 때문에 점 표기법보다 훨씬 강력하다. 그런데 작성하기가 번거롭다.
이런 이유로 프로퍼티 이름이 확정된 상황이고, 단순한 이름이라면 처음엔 점 표기법을 사용하다가 뭔가 복잡한 상황이 발생했을 때 대괄호 표기법으로 바꾸는 경우가 많다.
단축 프로퍼티
실무에서는 프로퍼티 값을 기존 변수에서 받아와 사용하는 경우가 종종 있다.
function makeUser(name, age){
return {
name : name,
age : age,
}
}
let user = makeUser("John", 30);
alert(user.name);
이렇게 변수를 이용해서 프로퍼티를 만들 시 코드를 짧게 줄일 수 있다.
function makeUser(name, age) {
return {
name, // name: name 과 같음
age, // age: age 와 같음
// ...
};
}
물론 함께 사용도 가능하다.
let user = {
name,
age: 30
}
프로퍼티 이름의 제약사항
변수 이름에는 예약어를 사용하면 안되지만 객체 프로퍼티에는 제약이 없다,
// 예약어를 키로 사용해도 괜찮습니다.
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 6
또한 문자형이나 심볼형에 속하지 않은 값은 문자열로 자동 형 변환 된다.
아래 예시를 살펴보자
let obj = {
0 : "test" // "0": "test"와 동일합니다.
}
// 숫자 0은 문자열 "0"으로 변환되기 때문에 두 얼럿 창은 같은 프로퍼티에 접근합니다.
alert(obj["0"]); // test
alert(obj[[0]); // test (동일한 프로퍼티)
객체 프로퍼티 키에 쓸 수 있는 문자열에는 제약이 없지만 역사적인 이유로 특별 대우를 받는 이름이 있다. __proto__ 이다.
let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); / [object Object] - 숫자를 할당했지만 값은 객체가 되었다.
프로퍼티 존재여부 확인하기 - in연산자
자바스크립트 객체의 중요한 특징중 하나는 다른 언어와는 달리, 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined를 발생 시킨 다는 것이다.
이런 특징을 응용하면 프로퍼티 존재 여부를 쉽게 확인할 수 있다.
let user = {}
lert( user.noSuchProperty === undefined ); // true는 '프로퍼티가 존재하지 않음'을 의미합니다.
undefined와 비교하지 않아도 in 연산자를 사용하여 프로퍼티 존재 여부를 확인할 수도 있다.
"key" in object
let user = { name: "John", age: 30 };
alert( "age" in user ); // user.age가 존재하므로 true가 출력됩니다.
alert( "blabla" in user ); // user.blabla는 존재하지 않기 때문에 false가 출력됩니다.
꼭 key 자리에는 따옴표로 감싸줘야한다! 만약 따옴표로 감싸주지 않으면 다른 값을 조사할 수도 있다.
let user = { age : 30 };
let key = "age";
alert( key in user ); // true, 변수 key에 저장된 값("age")을 사용해 프로퍼티 존재 여부를 확인합니다.
왜 굳이 in을 사용할까
대부분의 경우 undefined는 잘 동작하지만 가끔 이 방법이 실패할 때도 있다.
let obj = {
test : undefined
}
alert( obj.test ); // 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력됩니다. 그런데 프로퍼티 test는 존재합니다.
alert( "test" in obj ); // `in`을 사용하면 프로퍼티 유무를 제대로 확인할 수 있습니다(true가 출력됨).
obj.test 는 실제 존재하는 프로퍼티이기 때문에 in 연산자는 정상적으로 true를 반환한다. undefined는 값이 할당되지 않았을 경우에 사용하기 때문에 알수없거나 값이 비어있다는 것을 나타내고 싶을때는 null을 사용하자.
for…in 반복문
for…in 반복문을 사용하면 객체의 모든 키를 순회할 수 있다. 일반적인 for( ; ; ) 반복문과는 확연히 다르다.
문법
for (key in object) {
// 각 프로퍼티 키를 이용하여 본문을 출력함
}
사용
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) {
// 키
alert( key ); // name, age, isAdmin
// 키에 해당하는 값
alert( user[key] ); // John, 30, true
}
객체 정렬 방식
객체 프로퍼티는 어떤식으로 정렬될까? 답은 ‘특별한 방법으로’ 이다. 정수 프로퍼티는 자동으로 정렬되고, 그 외의 프로퍼티는 객체에 추가한 순서 그대로 정렬된다.
let codes = {
"49": "독일",
"41": "스위스",
"44": "영국",
// ..,
"1": "미국"
};
for (let code in codes) {
alert(code); // 1, 41, 44, 49
}
한편 키가 정수가 아닌 경우에는 작성된 순서대로 프로퍼티가 나열된다.
let user = {
name: "John",
surname: "Smith"
};
user.age = 25; // 프로퍼티를 하나 추가합니다.
// 정수 프로퍼티가 아닌 프로퍼티는 추가된 순서대로 나열됩니다.
for (let prop in user) {
alert( prop ); // name, surname, age
}
만약 위의 나라 번호가 입력 순서대로 나오게 하고싶다면 속임수를 쓰면 된다.
let codes = {
"+49": "독일",
"+41": "스위스",
"+44": "영국",
// ..,
"+1": "미국"
};
for (let code in codes) {
alert( +code ); // 49, 41, 44, 1
}
문제
문제 1
- user에 키가 name, 값이 John인 프로퍼티를 추가하세요.
- user에 키가 surname, 값이 Smith인 프로퍼티를 추가하세요.
let user = {
name : "John",
surname : "Smith",
}
- name의 값을 Pete로 수정해보세요.
user.name = "Pete"
- user에서 프로퍼티 name을 삭제하세요.
delete user.name
문제 2
객체에 프로퍼티가 하나도 없는 경우 true, 그렇지 않은 경우 false를 반환해주는 함수 isEmpty(obj)를 만들어 보세요.
아래와 같이 동작해야 합니다.
let schedule = {};
alert( isEmpty(schedule) ); // true
schedule["8:30"] = "get up";
alert( isEmpty(schedule) ); // false
답
const isEmpty = (obj) => {
for(let key in obj){
return false;
}
return true;
}
문제 3
모든 팀원의 월급에 대한 정보를 담고 있는 객체가 있다고 해봅시다.
let salaries = {
John: 100,
Ann: 160,
Pete: 130
}
모든 팀원의 월급을 합한 값을 구하고, 그 값을 변수 sum에 저장해주는 코드를 작성해보세요. sum엔 390이 저장되어야겠죠?
주의: salaries가 비어있다면 sum에 0이 저장되어야 합니다.
답
let salaries = {
John: 100,
Ann: 160,
Pete: 130
}
const values = Object.values(salaries);
let sum = 0;
for ( value of values ) {
if( value ) {
sum += value;
} else {
sum = 0;
}
}
alert(sum);
혹은
let salaries = {
John: 100,
Ann: 160,
Pete: 130
};
let sum = 0;
for (let key in salaries) {
sum += salaries[key];
}
alert(sum); // 390
문제 3
객체 obj의 프로퍼티 값이 숫자인 경우 그 값을 두 배 해주는 함수 multiplyNumeric(obj)을 만들어보세요.
// 함수 호출 전
let menu = {
width: 200,
height: 300,
title: "My menu"
};
multiplyNumeric(menu); // 아무것도 반환하지 않아도 괜춘
// 함수 호출 후
menu = {
width: 400,
height: 600,
title: "My menu"
};
답
let multiplyNumeric = (menu) => {
for( key in menu ) {
if(typeof(menu[key]) == 'number'){
menu[key] * 2
}
}
}
'JavaScript 개념' 카테고리의 다른 글
iterable 객체 (0) | 2024.04.30 |
---|---|
문자열 (1) | 2024.04.30 |
숫자형 (0) | 2024.04.29 |
원시값의 메서드 (0) | 2024.04.29 |
테스트 자동화와 Mocha (0) | 2024.04.29 |