
객체형 <-> 원시형 (오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있다)
{...}를 이용해 만든다.문자형) : 값(value) (모든 자료형) 쌍으로 구성된 프로퍼티를 여러 개 넣을 수 있다.빈 객체 만들기
let user = new Object(); // '객체 생성자' 문법
let user = {}; // '객체 리터럴' 문법
let user = { // 객체
name: "John", // 키: "name", 값: "John"
age: 30 // 키: "age", 값: 30
};
프로퍼티 값 얻기 => 점 표기법 사용하기
alert( user.name ); // John
alert( user.age ); // 30
프로퍼티 값 추가
user.isAdmin = true;
프로퍼티 값 삭제
delete user.age;
❗ 여러 단어를 조합해 프로퍼티 이름을 만든 경우엔 프로퍼티 이름을 따옴표로 묶어줘야 한다.
let user = {
name: "John",
age: 30,
"likes birds": true // 복수의 단어는 따옴표로 묶기
};
trailing(길게 늘어지는)쉼표 orhanging(매달리는)쉼표
마지막 프로퍼티 끝 뒤에 붙는 쉼표
👉 모든 프로퍼티가 유사한 형태를 보이기 때문에 프로퍼티 추가, 삭제, 이동이 쉬워진다.
❗const로 선언된 객체는 상수이기에 수정이 불가할까?❗
❌ 아니다! const로 선언된 객체는 수정될 수 있다.
const user = {
name: "John"
};
user.name = "Pete"; // (*)
alert(user.name); // Pete
const는 user의 값을 고정하지만, 그 내용은 고정하지 않기 때문이다.
👉 user = ... 와 같이 전체적으로 설정하려고 할 때만 오류를 발생시킨다!
let user = {
"likes birds": true // 복수의 단어는 따옴표로 묶기
};
alert(user.likes birds); // error
여러 단어를 조합해 프로퍼티 키를 만든 경우엔 점 표기법을 사용 불가 ❌
👉 대괄호 표기법을 사용하자!
alert(user["likes birds"]);
대괄호 표기법은 이렇게도 사용 가능! (점 표기법은 불가능함)
let key = "likes birds";
user[key] = true; // user["likes birds"] = true; 와 같다.
👉 코드를 유연하게 작성 가능
객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit]: 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아옴.
};
// fruit에 "apple"이 할당 되었다면 {"apple":5} 이므로
alert( bag.apple ); // 5
🔽 이렇게도 사용 가능!
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 // bag.appleComputers = 5
};
function makeUser(name, age) {
return {
name: name,
age: age,
// ...등등
};
}
이렇게 프로퍼티 이름과 값이 변수의 이름과 동일한 경우
프로퍼티 값 단축 구문을 사용하면
function makeUser(name, age) {
return {
name, // name: name 과 같음
age, // age: age 와 같음
// ...
};
}
이렇게 깔끔하게 사용할 수 있다!
변수 : for, let, return과 같은 예약어 사용 ❌
객체는 이런 제약이 없다!
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__
그러나__proto__는 예외로, 예상대로 작동하지 않는다!let obj = {}; obj.__proto__ = 5; // 숫자를 할당합니다. alert(obj.__proto__); // [object Object]참고 : 프로토타입 상속
in 연산자로 프로퍼티 존재 여부 확인하기자바스크립트 객체 : 다른 언어와 달리 존재하지 않는 프로퍼티에 접근해도 에러가 발생하지 않고 undefined를 반환
👉 이 성질을 이용해 프로퍼티 존재 여부 확인하기
let user = {};
alert( user.noSuchProperty === undefined ); // true
🔽 in 문법으로도 프로퍼티 존재 여부 확인이 가능하다!
"key" in object
let user = { name: "John", age: 30 };
alert( "age" in user ); // true
alert( "blabla" in user ); // false
이렇게 변수 값을 이용해서도 가능
let user = { age: 30 };
let key = "age";
alert( key in user ); // true, 변수 key에 저장된 값("age")을 사용해 프로퍼티 존재 여부를 확인
❓ 그런데 왜 undefined랑 비교해도 충분한데 in 연산자가 있는거지?
undefined와의 비교로 검사했을 때 실패하는 예쩨
let obj = {
test: undefined
};
alert( obj.test === undefined ); // true --> 우리가 예상하기로는 프로퍼티가 있으니까 false여야 했는데 ㅠㅠ
alert( "test" in obj ); // true
값이 undefined여서, 값에 접근했을 때 undefined를 뱉어버린다.
for...in 반복문모든 키 순회하기
for (key in object) {
}
ex)
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) {
alert( key ); // name, age, isAdmin
alert( user[key] ); // John, 30, true
}
프로퍼티엔 순서가 있을까? 반복문은 프로퍼티를 추가한 순서대로 실행될까? 이 순서는 항상 동일할까?
👉 정수 프로퍼티는 자동으로 정렬되고, 그 외 프로퍼티는 객체에 추가한 순서 그대로 정렬된다.
정수 프로퍼티
변형 없이 정수에서 왔다 갔다 할 수 있는 문자열// 함수 Math.trunc는 소수점 아래를 버리고 숫자의 정수부만 반환합니다. alert( String(Math.trunc(Number("49"))) ); // '49'가 출력됩니다. 기존에 입력한 값과 같으므로 정수 프로퍼티입니다. alert( String(Math.trunc(Number("+49"))) ); // '49'가 출력됩니다. 기존에 입력한 값(+49)과 다르므로 정수 프로퍼티가 아닙니다. alert( String(Math.trunc(Number("1.2"))) ); // '1'이 출력됩니다. 기존에 입력한 값(1.2)과 다르므로 정수 프로퍼티가 아닙니다.
정수 프로퍼티 예제
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
}
+codecode 앞에 붙어있는+는 어떤 문법이지?
➕ 참고
일반 객체 외 다양한 객체
Array – 정렬된 데이터 컬렉션을 저장할 때 쓰임Date – 날짜와 시간 정보를 저장할 때 쓰임Error – 에러 정보를 저장할 때 쓰임객체는 ‘참조에 의해(by reference)’ 저장되고 복사된다.
<-> 원시값은 '값 그대로' 저장, 할당되고 복사된다.
원시값 ex)
let message = "Hello!";
let phrase = message;
두 개의 독립된 변수에 각각 문자열 "Hello!" 저장

객체 ex)
let user = {
name: "John"
};
변수에 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어있는 '메모리 주소’인 객체에 대한 '참조 값’이 저장

let user = { name: "John" };
let admin = user; // 참조값을 복사

👉 그래서!! 객체에 접근하거나 조작할 때 user, admin 변수에서 모두 가능하다.
admin.name = 'Pete'; // 'admin' 참조 값에 의해 변경됨
alert(user.name); // 'Pete'가 출력됨. 'user' 참조 값을 이용해 변경사항을 확인함
ex1) 같은 객체를 참조하기 때문에 비교시 참 반환
let a = {};
let b = a; // 참조에 의한 복사
alert( a == b ); // true
alert( a === b ); // true
ex2) 독립된 두 객체이기 때문에 비교시 거짓 반환
let a = {};
let b = {}; // 독립된 두 객체
alert( a == b ); // false
그런데 기존에 있던 객체와 똑같으면서 독립적인 객체를 만들고 싶다면?
👉 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 복사
let user = {
name: "John",
age: 30
};
let clone = {}; // 새로운 빈 객체
// 순회해서 복사
for (let key in user) {
clone[key] = user[key];
}
clone.name = "Pete"; // clone의 데이터를 변경
alert( user.name ); // "John" --> 그럼에도 기존 객체에는 여전히 John이 있음!
🔽 Object.assign을 사용해도 된다
Object.assign(dest, [src1, src2, src3...])
dest : 목표하는 객체src1, ..., srcN : 복사하고자 하는 객체src1, ..., srcN 의 프로퍼티를 dest에 복사.
dest 반환
❗ 목표 객체에 동일한 이름을 가진 프로퍼티가 있는 경우엔 기존 값이 덮어씌워짐
ex1)
let user = { name: "John" };
let permissions1 = { canView: true };
let permissions2 = { canEdit: true };
// permissions1과 permissions2의 프로퍼티를 user로 복사
Object.assign(user, permissions1, permissions2);
// now user = { name: "John", canView: true, canEdit: true }
ex2)
let user = {
name: "John",
age: 30
};
let clone = Object.assign({}, user);
그런데 프로퍼티가 원시값이 아니라 다른 객체에 대한 참조 값이라면?
다른 객체를 참조하고 있는 그 프로퍼티는 같은 객체를 참조하게 된다! ( 완전히 독립된 객체로 복사할 수 없는 것 )
let user = {
name: "John",
sizes: {
height: 182,
width: 50
}
};
let clone = Object.assign({}, user);
alert( user.sizes === clone.sizes ); // true
// user와 clone는 sizes를 공유
user.sizes.width++; // 프로퍼티를 변경합니다.
alert(clone.sizes.width); // 51, 다른 객체에서 변경 사항을 확인 가능
❓ 그럼 이 문제를 어떻게 해결하지?
▶ 깊은 복사 : user[key]의 각 값을 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야 한다!
➕ 참고
자바스크립트 라이브러리lodash의 메서드인_.cloneDeep(obj)을 사용하면 깊은 복사를 처리할 수 있다.