key
에는 문자형, value
에는모든 자료형이 허용된다.let user = new Object();
let user = {};
let user = {
name: "승경씨", // 키: "name", 값: "승경씨"
age: 20, // 키: "age", 값: 30
"like fruit" : "yes" // ✅ 복수의 단어는 따옴표로 묶어야 한다.
};
delete user.age; // ✅ delete 연산자를 사용해서 프로퍼티를 삭제할 수 있다.
📍 상수 객체는 수정될 수 있다.
const user = { name: "승경씨" }; user.name = "Heather";
const는 user의 값을 고정하지만, 내용은 고정하지 않기 때문에
user=..
이렇게 전체적으로 설정하려고 할 때만 오류를 발생시킨다
코테 문제를 풀면서도 왕왕 볼 수 있는 문법인데, 아주 편리하다.
위 객체 사용 예시에서 선언한 like fruit
를 가져올 때
user.like fruit = false;
이와 같이 써주게 되면 에러가 발생한다.
.
은 유효한 key인 경우에만 사용 가능한데, 유효한 key에는
key가 유효하지 않을 경우에 사용할 수 있는 방법이 대괄호 표기법
이다.
let user = {};
// set
user["like fruit"] = true; // ✅ 대괄호 표기법 안에서 문자열을 쓸 때는 꼭 따옴표로 묶어줘야한다.
// get
alert(user["likes fruit"]); // true
대괄호 표기법을 사용하면 다으모가 같이 변수를 key로 사용할 수 있다.
let key = "like fruit"
user[key] = true; // ✅ 대괄호 표기법 안에서 문자열을 쓸 때는 꼭 따옴표로 묶어줘야한다.
변수는 런타임에 평가가 되기 때문에 사용자의 입력값 변경 등에 따라 값이 바뀔 수 있는데, 이 점을 이용해 유연하게 코드를 작성할 수 있다.
let user = {
name: "Heather",
age: 20
};
let key = prompt("사용자의 어떤 정보를 얻고 싶으신가요?", "name");
// 변수로 접근
alert( user[key] ); // Heather (프롬프트 창에 "name"을 입력한 경우)
점 표기법을 이용하면 해당 방식은 불가능하다.
let user = {
name: "Heather",
age: 23
};
let key = "name";
alert( user.key ) // undefined
객체의 key가 대괄호로 둘러싸여 있는 경우, 이를 계산된 프로퍼티
라고 부른다
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");
let bag = {
[fruit]: 5, // ✅ 변수 fruit에서 프로퍼티 이름을 동적으로 받아옴
};
alert( bag.apple ); // ✅ fruit에 "apple"이 할당되었다면 값을 가져온다.
다음과 같이 구현할 수도 있지만, 계산된 프로퍼티를 사용하는 것이 더 간단해 보인다.
let bag = {};
bag[fruit] = 5;
function makeUser(name, age) {
return {
name: name,
age: age,
// ...등등
};
}
다음과 같이 리턴하는 객체의 key
값과 변수명이 같을 때 name : name
으로 써주지 않고 다음과 같이 줄여 쓸 수 있다.
function makeUser(name, age, gender) {
return {
name, // ✅ name: name 과 같음
age,
gender : gender, // ✅ 일반 프로퍼티와 단축 프로퍼티를 함께 사용할 수도 있다.
// ...
};
}
for
, let
, return
같은 예약어를 key 값으로 사용할 수 있으며, 어떠한 문자형, 심볼형 값도 key가 될 수 있다. let obj = {
0: "zero" // ✅ 0이 "0"으로 자동 형변환되어 "0": "zero"와 동일
};
alert( obj["0"] ); // "zero"
alert( obj[0] ); // "zero"
in
연산자로 프로퍼티 존재여부 확인일치 연산자를 사용해 "name" === undefined
로 프로퍼티 존재 여부를 확인할 수도 있지만, 가끔 이 방법이 실패하기도 한다.
let obj = {
test: undefined
};
//✅ undefined가 할당된 값이므로 undefined가 출력된다. 하지만 test는 존재한다. 혼돈을 줄 수 있다.
alert( obj.test );
이 경우 in
연산자를 사용하면 좋다.
let user = {
name: "Heather",
age: 23
};
// ✅ 프로퍼티 명은 따옴표로 감싼다
alert ("name" in user); // true
let user = {
name: "Heather",
age: 24,
};
for (let key in user) {
// 키
alert( key ); // name, age
// 키에 해당하는 값
alert( user[key] ); // Heather, 24
}
반복변수명 (상기 코드에서는 key)는 자유롭게 정할 수 있다. let num in numList
와 같이 쓸 수도 있다.
객체의 프로퍼티는 항상 객체에 추가한 순서 그대로 정렬이 될까?
아니다.
그 외 프로퍼티는 객체에 추가한 순서대로 정렬되지만, 정수 프로퍼티
는 자동으로 정렬이 된다.
let codes = {
"49": "독일",
"41": "스위스",
"44": "영국",
// ..,
"1": "미국"
};
for (let code in codes) {
alert(code); // ✅ 1, 41, 44, 49
}
for (let code in codes) {
alert(+code); // ✅ key가 정수 프로퍼티가 아니도록 숫자로 바꿔준다.
}
📍 정수 프로퍼티란
정수 프로퍼티
라는 용어는 변형 없이 정수에서 왔다 갔다 할 수 있는 문자열을 의미한다.
"49"는 정수로 변환해도, 변환한 정수를 다시 문자열로 바꿔도 변형이 없이 49이지만,
"+49"는 정수로 변환하면 49로 원래 값과는 달라지기에 정수 프로퍼티가 아니다.
원시값은 '값 그대로' 저장/할당/복사되지만, 객체형은 참조에 의해 저장되고 복사된다.
let message = "Hello!";
let phrase = message;
이렇게 문자열을 변수에 저장한 경우에는
다음과 같이 독립된 변수에 각각 Hello!
가 저장된다.
하지만 객체의 경우에는 객체 자체는 메모리 어딘가에 저장이 되고, 변수에는 객체를 참조할 수 있는 값이 저장된다.
let user = { name: "John" };
let admin = user; // 참조값을 복사함
따라서 다음과 같은 코드로 객체를 조작하고 접근할 수 있다.
let user = { name: 'Heather' };
let admin = user; //✅ admin, user는 같은 주소를 가리킨다.
admin.name = 'Eunice';
객체 비교 시 ==
와 ===
는 동일하게 동작한다.
두 객체가 동일한 객체 (즉, 두 변수가 하나의 객체를 가리키는 경우) 참을 반환한다.
let a = {};
let b = a; // ✅ 참조에 의한 복사
alert( a == b ); // true, 두 변수는 같은 객체를 참조합니다.
alert( a === b ); // true
하지만 다음과 같은 경우에는 두 객체가 같아보이지만 각각 주소가 다른 객체이기 때문에 비교시 false를 반환한다.
let a = {};
let b = {}; // 독립된 두 객체
alert( a == b ); // false
참조에 의한 복사를 이용해 객체가 할당된 변수를 복사하면, 동일한 객체에 대해 참조하는 값이 하나 더 만들어질 뿐이다.
만약 기존에 있던 객체와 동일하지만, 독립적인 객체를 만들고 싶다면 어떻게 해야할까?
let clone = {}; // 새로운 빈 객체
// 빈 객체에 user 프로퍼티 전부를 복사해 넣습니다.
for (let key in user) {
clone[key] = user[key];
}
다음과 같이 객체를 순회하며 원시 수준까지 프로퍼티를 복사할 수도 있고
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 }
Object.assign
을 이용할 수도 있다.
Object.assign(dest, [src1, src2, src3...])
에서 첫번째 인자에는 목표로 하는 객체가 들어가고, src1, src2, src3에는 복사하고자하는 객체가 들어간다.
만약 목표 객체(dest)에 동일한 이름을 가진 프로퍼티가 있다면 기존 값에 새로운 값이 덮어 씌워진다.
let user = { name: "John" };
Object.assign(user, { name: "Pete" });
alert(user.name); // user = { name: "Pete" }
객체 리터럴 안에서 메서드를 선언할 때 다음과 같은 두 방법을 사용할 수 있다.
user = {
sayHi: function() {
alert("Hello");
}
};
// ✅ 단축 구문
user = {
sayHi() { // "sayHi: function()"과 동일
alert("Hello");
}
};
메서드 내부에서 this 키워드를 사용하면 객체에 접근할 수 있다.
let user = {
name: "John",
age: 30,
sayHi() {
// ✅ 'this'는 '현재 객체'를 나타냅니다.
alert(this.name); // ✅ alert(user.name);와 동일
}
};
alert(user.name)
는 외부 변수이기 때문에 만약 객체 외부에서 user = null
과 같은 재할당이 일어난다면 에러가 발생할 것이다.
따라서 이 경우에는 this를 사용하는 게 더 좋겠다.
자바스크립트에서 this의 값은 런타임에 결정된다.
어려운 개념이 아니라 단순히 메서드가 어디서 정의되었는지에 상관없이 this는 ‘점 앞의’ 객체가 무엇인가에 따라 ‘자유롭게’ 결정된다는 의미이다.
let user = { name: "John" };
let admin = { name: "Admin" };
function sayHi() {
alert( this.name );
}
// ✅ 별개의 객체에서 동일한 함수를 사용함
user.f = sayHi;
admin.f = sayHi;
// ✅ 'this'는 '점(.) 앞의' 객체를 참조하기 때문에 this 값이 각각 달라진다
user.f(); // John (this == user)
admin.f(); // Admin (this == admin)