자바스크립트에는 8개 자료형이 있는데 이 중 7개는 오직 하나의 데이터(문자열, 숫자)만 담을 수 있어 원시형(Primitive type)이라고 부른다.
하지만 객체형은 원시형과 달리 다양한 데이터를 담을 수 있다. 키로 구분된 데이터집합이나 복잡한 개체를 {}
를 이용하여 저장 할 수 있다.
중괄호 안에는 '키(key):값(value)' 쌍으로 구성된 프로퍼티를 여러개 넣을 수 있는데, key
에는 문자형, value
에는 모든 자료형이 허용된다.
let user = new Object(); // 객체 생성자 문법
let user = {}; // 객체 리터럴 문법(주로 이 방법 사용)
let user = {
name : 'John',
age : 30
};
alert( user.name ); // John
alert( user.age ); // 30
프로퍼티 값을 추가 혹은 삭제 또한 할 수 있다.
user.isAdmin = true;
delete user.age;
여러 단어를 조합해 프로퍼티 이름을 만든 경우는 프로퍼티 이름을 따옴표로 묶어줘야 한다.
let user = {
name : 'John',
age : 30,
"like birds":true
};
상수 객체는 수정 될 수 있다.
const
로 선언된 객체 는 수정 될 수있다. 헷갈리지 말자!
const user = {
name : "John",
};
user.name = "Pete";
alert(user.name); // Pete
const
는 user
의 값을 고정하지만, 그 내용은 고정하지 않는다.
여러 단어를 조합해 프로퍼티 키를 만든 경우에는, 점 표기법을 사용해 프로퍼티 값을 읽을 수 없다.
user.likes birds = true // Error
이러한 경우에는 점 표기법 대신 '대괄효 표기법' 방법을 사용 할 수 있다.
let user = {};
//set
user["likes birds"] = true;
//get
alert(user["likes birds"]); // true
//delete
delete user["like birds"]);
변수를 키로 사용할 수 도 있다.
let user = {
name : "John",
age : 30
};
let key= prompt("Which information do you want?", "name");
alert(user[key] ); // John(프롬프트 창에 "name"을 입력한 경우)
하지만 점 표기법은 이런 방식이 불가능하다.
let user = {
name: "John",
age:30
};
let key = "name";
alert( user.key ) //undefined
객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는경우, 이를 계산된 프로퍼티라고 부른다.
let fruit = prompt("which fruit do you want?", "apple");
let bag = {
[fruit]: 5, // 변수 fruit에서 프로퍼티의 이름을 동적으로 받아온다.
};
alert( bag.apple); // fruit에 "apple"이 할당되었다면, 5가 출력 된다.
function makeUser(name, age){
return {
name: name,
age: age,
};
}
let user = makeUser("John", 30);
alert(user.name); // John
위 코드와 같이 이름과 값의 변수 이름이 동일 할 때는 name:name
이 아닌 name
만 적어도 프로퍼티를 설정 할 수 있다.
function makeUser(name, age){
return {
name,
age,
};
}
//일반 프로퍼티와 단축 프로퍼티 함께 사용도 가능
function makeUser(name, age){
return {
name,
age: 30
};
}
변수 이름으로는 'for', 'let', 'return' 같은 예약어를 사용하면 안되지만 객체 프로퍼티엔 이런 제약이 없다.
let obj = {
for : 1,
let : 2,
return : 3
};
alert( obj.for + obj.let + obj.return); // 6
문자형이나 심볼형에 속하지 않은 값은 문자열로 자동 형 변환이 된다.
예를 들어, 키에 숫자 0
을 넣으면 문자열 "0"
으로 자동변환 된다.
let obj = {
0:"test"
};
alert( obj["0"] ); // test
alert( obj[0] ); // test
이와 객체 프로퍼티 키에 쓸 수 있는 문자열에 제약이 없지만, 예외가 하나있다. 바로 __proto__
이다. 역사적인 이유때문이라고 한다.
자바스크립트 객체 특징 중 하나는 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고 undefined
를 반환한다는 것이다.
let user = {};
alert(user.noSuchProperty === undefined); // true
// in을 사용하여 프로퍼티 존재 여부도 확인이 가능하다
let user = {
name : "John",
age : 30
};
alert( "age" in user ); // user.age 존재하므로 true
alert( "abc" in user ): // false
in
왼쪽에는 반드시 프로퍼티 이름이 와야한다. 프로퍼티 이름은 보통 따옴표로 감싼 문자열이다.
따옴표를 생략하면 아래 예시와 같이 엉뚱한 변수가 조사 대상이 된다.
let user = {
age : 30
};
let key = "age";
alert( key in user ); // true, 변수 key에 저장된 값("age")를 사용해 프로퍼티 존재 여부를 확인 할 수 있다.
대부분 경우, 일치 사용자를 사용해 프로퍼티 존재 열부를 알아낼 수 있지만, 가끔 실패 하는경우가 있다. 이럴 때 in
을 사용 할 수 있다.
let obj = {
test : undefined
};
alert( obj.test ); // 값이 'undefined'이므로, 얼럿 창에 undefined가 출력 된다.
alert( "test" in obj); // true가 출력
for..in
반복문을 사용하면 객체의 모든 키를 순회 할 수 있다.
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" };
let admin = user;
admin.name = 'Pete'
alert(user.name) // Pete 출력됨
변수에 객체가 그대로 저장되는것이 아니라, 객체가 저장되어 있는 '메모리 주소'인 객체에 대한 '참조 값'이 저장된다.
객체 비교 시 동등 연산자 ==
와 일치 연산자 ===
는 동일하게 동작한다.
비교 시 피연산자인 두 객체가 동일한 객체인 경우에 참을 반환
let a = {};
let b = a;
alert( a == b ); // true
alert( a === b ); // true
기존에 있던 객체와 똑같으면서 독립적인 객체를 만들려면 어떻게 해야할까?
자바스크립트는 객체 복제 내장 메서드를 지원하지 않기 때문에 조금 어렵다.
정말 복제가 필요하면 새로운 객체를 만든 다음 기존 객체의 프로퍼티들을 순회해 원시 수준까지 프로퍼티를 복사 해야한다.
let user = {
name:"Jin",
age:29
};
let cloe = {};
// 빈 객체에 user 프로퍼티를 전부 복사
for (let key in user) {
clone[key] = user[key];
}
clone.name = "Pete"
alert(user.name); // 기존 객체에는 여전히 Jin이 있다.
Object.assign(dest, [src1, src2, src3...])
dest
는 목표로 하는 객체src1, ...., srcN
은 복사하고자 하는 객체.src1, .. , srcN
의 프로퍼티를 dest
에 복사.dest
를 반환.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 }
목표 객체(user
)에 동일한 이름을 가진 프로퍼티가 있는 경우에는 기존 값이 덮어 씌워 진다.
let user = { name: "John" };
Object.assign(user, { name: "Pete" });
alert(user.name); // user = { name: "Pete" }