JS
에는 8가지의 자료형 타입이 있고, 이중 객체를 제외한 7개의 자료형은 오직 하나의
데이터 (문자열,숫자형 등)만 담을 수 있어 원시형(primitive type)이라고 부릅니다.
그런데 객체형은 원시형과 다르게 다양한 자료형을 저장할 수 있습니다.
키로 구분된 데이터의 집합이나 복잡한 객체(entity)를 저장할 수 있습니다.
⭐ 객체의 필요성
배열을 사용하기엔 알맞지 않는 요소를 생성할 때 사용합니다.
예를 들면 한식이라는 카테고리에 음식명, 칼로리, 지방, 단백질등등 여러가지 데이터에
대한 값이 필요할 때, 키와 쌍으로 연결지어서 구분하면 편리합니다.
배열로 사용한다면 어떤 주제에 대한 값인지 분명하게 확인하기 어렵기 때문입니다.
객체는 { } 중괄호를 사용해 만들고, { } 안에는 객체를 구성하는 프로퍼티가 존재합니다.
프로퍼티는 키와 값으로 이루어져 있습니다.
키는 프로퍼티를 가르키는 이름표이고, 문자열이나 심볼형을 사용합니다.
값은 데이터를 할당할 수 있고 객체를 포함한 모든 자료형이 허용 됩니다.
🔔 객체(object), 프로퍼티(property), 키(key), 값(value)
서랍장을 상상해서 객체 이해하기
서랍장안에는 무수한 파일들이 있습니다. 파일을 찾으려면 이름표를 확인해서 손쉽게
파일을 찾을 수 있습니다. 객체도 마찬가지로, 객체안에 수많은 프로퍼티들이 있습니다.
원하는 프로퍼티만을 찾고 싶을 때는, 프로퍼티에 붙은 키를 이용해서 손쉽게 프로퍼티를
찾을 수 있습니다.
서랍장 = 객체
파일들 = 프로퍼티
이름표 = 프로퍼티의 키
❤️ 객체 생성 방법
let user = new object(); // 생성자 함수를 사용해서 객체 생성
let user = {}; // 리터럴 방식으로 객체 생성
/* */
new object();
1) new 연자를 사용해서 object() 함수를 호출함 > new 연산자가 붙은 함수는 생성자 함수가 된다
2) 생성자 함수는 내부에서 this라는 객체가 생성된다.
{};
1) { } 중괄호를 사용해서 객체를 생성하는 방법은, 객체 리터럴 방식이라고 한다.
2) 생성자 함수를 사용하지 않고 사용 가능
{ }
중괄호를 사용해서 객체를 만드는 방식을 객체 리터럴 방식이라고 합니다.
객체는 프로퍼티 키와 값으로 구성되어 있습니다.
프로퍼티는 .
점 표기법과 []
대괄호 표기법으로 접근할 수 있습니다.
let user = { // 객체 리터럴 방식으로 선언
name: "John", // 키 : name | 값 : "John"
age: 30 // 키 : age | 값 : 30
};
/* */
콜론(:)을 기준으로, 좌측에는 키가 우측에는 값이 들어갑니다.
프로퍼티의 키는 프로퍼티의 이름 또는 식별자라고 말합니다.
위에서
user
객체를 이미지로 표시해보면 아래와 같습니다.
user
라는 객체에 2개의 프로퍼티가 있고, 각 프로퍼티의 키(이름표)는
name
과age
입니다. 프로퍼티의 값을 확인 하려면, 프로퍼티의 키를 호출하면 됩니다.// 프로퍼티 값 얻기 alert( user.name ); // user 객체의 name 프로퍼티 안에 있는 값 : John alert( user.age ); // ...~ 값 : 30
.
표기법이나 []
대괄호 표기법으로 프로퍼티를 생성할 수 있다.user.isAdmin = true; // user 객체에 isAdmin 프로퍼티 키를 생성, 값으로는 true을 할당
/* */
프로퍼티의 값에는 논리형 뿐만 아니라 모든 자료형이 올 수 있습니다.
delete
연산자로 프로퍼티 삭제delete user.age; // user 객체의 age 프로퍼티가 삭제 됩니다.
/* */
delete 연산자를 사용하면 객체의 프로퍼티를 삭제할 수 있습니다.
"
따옴표를let user = {
name: "John",
age: 30,
"true boolean": true // 복수의 단어는 " " 따옴표로 묶어줍니다.
};
객체안에 여러 개의 프로퍼티가 존재할 수 있는데, 프로퍼티 마다 ,
쉼표를 통해서 구분
해줘야 합니다.
객체의 마지막 프로퍼티는 ,
을 사용하지 않아도 됩니다.
let user = {
name: "John",
age: 30, // (*)
};
/* */
(*)
프로퍼티 간의 구분은 쉼표로 구분 짓습니다. 이런 쉼표를 trailing(길게 늘어지는) 혹은
hanging(매달리는) 쉼표라고 부릅니다. 객체의 마지막 프로퍼티에는 쉼표를 붙여도 되고
붙이지 않아도 됩니다.
const user = { // user 라는 객체명은 상수기에 변경할 수 없다.
name: "John"
};
user.name = "Pete"; // 상수인 객체도 프로퍼티는 변경할 수 있다.
alert(user.name); // 출력 : Pete
/* */
1) 상수로 선언된 객체명 `user`는 변경할 수 없다.
2) 하지만 객체안의 프로퍼티는 상수여도 변경할 수 있다.
.
표기법은 프로퍼티의 키가 따옴표로 구성되어 있다면 읽을 수 없습니다.
대괄호 표기법은 프로퍼티의 키가 어떻게 구성되어 있던지 읽을 수 있습니다.
user.true boolean = true // 오류가 발생합니다.
/* */
1) JS 에서는 공백이 있는 단어를 읽을 수 없습니다. > 따옴표를 사용해야 인식 합니다.
2) user.true 까지는 읽지만, 뒤에 공백이 있기에 boolean를 읽을 수 없다.
3) 위 코드는 "true boolean" 으로 따옴표로 묶게되면 JS가 인식할 수 있습니다.
4) 다만, 점 표기법은 읽을 수 없다. 대괄호 표기법을 사용해야 합니다.
alert(user."true boolean") X
alert(user["true boolean"] O
🔔
.
표기법과[]
대괄호 표기법
.
표기법은 키의 이름이 유효한 변수 식별자인 경우에만 접근할 수 있습니다.
즉, 공백이 있어선 안되고 숫자로 시작하지 말아야하며 특수문자는 $와 _만 허용합니다.
[]
대괄호 표기법은 키에 어떤 문자열이나 공백이 있던지 상관없이 접근할 수 있다.
대괄호 표기법은 따옴표가 있어도 접근할 수 있습니다.
대괄호 표기법으로 프로퍼티를 생성 할 때는, 키의 이름은 "
따옴표로 묶어줘야 합니다.
( 따옴표의 종류는 상관 없습니다 )
❤️ 대괄호 표기법 프로퍼티 생성
let user = {}; // 객체 선언
// 프로퍼티 생성
user['age'] = 30; // 키 : age | 값 : 30
user['true boolean'] = true; // 키 : true boolean | 값 : true
// 프로퍼티 출력
alert(user['age']);
alert(user['true boolean']);
// 프로퍼티 삭제
delete user.age;
delete user['true boolean'];
let string = "likes birds"; // 변수 선언
let user = {}; // 객체 선언
user[string]; // user 객체에 string 변수의 값을 프로퍼티 이름으로 생성합니다.
user['likes birds'] = true; // 프로퍼티에 값 할당, user[string]으로도 접근할 수 있습니다.
console.log(user); // { 'likes birdes': true } , user 객체안의 내용물
console.log(user[string]); // true 출력
/* */
대괄호 표기법을 사용하면 변수 뿐만 아니라 모든 표현식의 결과 값을
프로퍼티의 키로 사용할 수 있습니다.
변수 뿐만 아니라 모든 표현식의 결과를 프로퍼티의 키로 사용할 수 있습니다.
사용자로부터 값을 입력받고, 그 값을 변수에 저장하는 prompt
함수도 예외는 아닙니다.
let user = { // 객체 user 선언
name: "John",
age: 30
};
let key = prompt('사용자의 정보를 알아봅시다.', "name"); // 사용자가 name을 입력
alert( user[key] ); // user.name 프로퍼티를 호출 > "John" 출력
/* */
1) 사용자로부터 입력받은 값을 토대로, 객체안에 프로퍼티를 생성하거나 접근할 수 있다.
2) 사용자가 'name'을 입력한다면, key 변수에 그 값이 반환된다.
user[key]는 user['name']과 같습니다.
즉, user[key]를 호출하면 user.name에 있는 "John" 이 출력 된다.
3) 사용자가 'age'를 입력 했다면, user['age']가 되어서 30의 값이 출력됩니다.
4) 'age' 혹은 'name'이 아닌 다른 값을 입력한다면 alert( user[key] )는
user 객체 안에 사용자가 입력한 값이 프로퍼티로 구성되있지 않다면 `undefined`를 반환할 것입니다.
✅
.
표기법으로는 변수를 프로퍼티 키로 사용할 수 없다.
alert( user.key )
로 구현헀다면,key
변수의 값을 참조하는 것이 아니라user
객체
안에key
라는 프로퍼티를 참조하므로 오류가 발생한다.
객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우
이를 계산된 프로퍼티(computed property)라고 부릅니다.
동적으로 어떤 값을 할당 받아서 값에 따라 프로퍼티 키의 이름이 항상 변경될 수 있다.
❤️ 동적인 값으로 프로퍼티를 생성
let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple"); // 사용자는 'apple'을 입력
let bag = {
[fruit]: 5, // [fruit]란 fruit 변수의 값을 동적으로 받아옵니다. 즉, 'apple': 5와 같다.
};
alert( bag.apple ); // bag[fruit] 또는 bag.apple로 접근할 수 있다.
/* */
(1)
사용자가 입력한 값 (예시 : apple)을 fruit 변수에 저장
(2)
bag[fruit]는, fruit 변수의 값을 프로퍼티 이름으로 저장합니다.
즉, 사용자가 입력한 값을 토대로 bag.apple이 프로퍼티 키가 됩니다.
(3)
즉, [fruit]는 ['apple']과 같다.
bag[fruit] == bag['apple'] 또는 bag.apple
❗ 사용자가 입력한 값을 변수를 통해서 동적으로 받아오는 것은 대괄호 표기법만 가능하다.
let fruit = 'apple';
let bag = {
[fruit + 'Computers']: 5 // 이 프로퍼티 키는 'appleComputers' 이 된다.
};
/* */
대괄호 표기법은 프로퍼티의 키와 값에 제약을 없애주기 때문에 점 표기법보다 훨씬 강력합니다.
다만 작성하기가 어렵다는 단점이 있습니다.
🔔 점 표기법과 대괄호 표기법
프로퍼티의 이름이 확정된 상황이라면 점 표기법을 사용하고, 복잡한 상황이 생긴다면
대괄호 표기법으로 변경해서 사용하는 경우가 이상적입니다.
function makeUser(name, age) {
return { // 중괄호를 사용하면 프로퍼티를 생성할 수 있습니다. 그 값을 반환
name: name, // 프로퍼티의 키는 name이며 값은 인수로 받아온 name('John')
age: age // 프로퍼티의 키는 age이며 값은 인수로 받아온 age(30)
};
}
let user = makeUser("John", 30);
alert(user.name); // 출력 : John
매개변수와 프로퍼티 키의 이름이 동일하면, 단축해서 사용할 수 있다.
↓ 단축 사용 예시
function makeUser(name, age) {
return {
name, // 프로퍼티의 이름을 매개변수 name으로 사용 ( 매개변수 name : "John" )
age, // 프로퍼티의 이름을 매개변수 age로 사용 ( 매개변수 age : 30 )
// ...
};
}
let user = makeUser("John", 30);
alert(user.name); // 출력 : John
// user.name은 프로퍼티 name을 호출한다. 여기서 프로퍼티 name은 매개변수 name과 동일한 이름이므로
// name에 접근하면 매개변수 name의 값이 호출 된다 > John
let d = {
name, // name: name과 같다.
age : 30
};
일반적으로 변수의 이름에는 예약어를 사용하면 안됩니다. (let, return, for 등)
프로퍼티를 사용하면 키를 정의할 때 제약 사항이 없습니다.
let obj = {
for: 1,
let: 2,
return: 3
};
alert( obj.for + obj.let + obj.return ); // 출력 : 6
/* */
프로퍼티의 키 이름에는 아무런 제약사항이 없습니다.
어떤 문자형이나 심볼형도 키의 이름으로 사용할 수 있습니다.
문자형이나 심볼형에 속하지 않는 자료형은 문자열로 자동 형 변환됩니다.
만약 키의 이름에 숫자 0을 넣으면 문자형 '0' 으로 형변환 됩니다.
객체에서 프로퍼티를 생성할 때 키의 이름은 문자형이나 심볼형으로 사용해야 한다.
다른 자료형이 온다면 됩니다.
let obj = {
0: "test" // 자료형이 숫자형이기에 문자형으로 형 변환 된다. ( "0": "test"와 동일 )
};
alert( obj[0] ); // "test" 출력, 정수 0을 문자열 '0'으로 변경해서 프로퍼티 키를 찾는다.
alert( obj['0'] ); // "test" 출력
__proto__
?__proto__
라고 정의하게 되면 객체가 할당된다.let obj = {};
obj.__proto__ = 5;
alert(obj.__proto__); // 출력 : object Obejct, 숫자를 할당 했지만 객체가 되었습니다.
/* */
역사적인 이유로 특별대우 받는 이름이 __proto__ 입니다.
이 문제는 추후 포스팅에에서 다뤄보겠습니다..
JS
객체의 중요한 특징 중 하나는 다른 언어와는 다르게 존재하지 않는 프로퍼티에
접근하려 해도 오류 대신에 undefined
를 반환 한다는 것 입니다.
이러한 특징을 사용해서 프로퍼티가 존재하는지 유무를 확인할 수 있습니다.
let user = {};
alert( user.noSuchProperty === undefined );
// true : 프로퍼티가 존재하지 않음을 의미합니다.
// 해당 프로퍼티의 이름이(키) 존재한다면 false가 나오겠죠.
in
연산자연산자 in
을 사용하면, 프로퍼티가 존재하는지 유무에 대해 확인할 수 있습니다.
반환 값으로는 true
또는 false
를 반환합니다.
"key" in obejct // in 연산자 구문 : "프로퍼티 키" in 객체명
let user = { name: "John", age: 30 };
alert("age" in user); // user 객체안에 "age" 라는 프로퍼티가 있습니까? > true
alert("noname" in user); // user 객체안에 "noname" 라는 프로퍼티가 있습니까? > false
in
연산자 사용 규칙in
연산자 좌측에는 프로퍼티의 이름(키)가 존재해야 합니다.let user = { age: 30 };
let key = "age";
alert( key in user ); // 출력 결과 : true
/* */
alert( key in user );
1) 따옴표가 없으므로 key 라는 변수를 찾습니다. > key 변수에는 "age" 라는 값이 있다.
2) key 변수의 값을 가져옵니다. ("age" in user) > user 객체 안에 age 라는 프로퍼티가 있습니까?
> true
3) 따옴표를 사용하면 user 객체 안에 'key' 라는 프로퍼티가 있는지 검사하므로 오류가 발생
for..in
반복문은 객체의 모든 프로퍼티를 확인할 수 있다.
in
연산자 + for
문 객체의 모든 프로퍼티를 확인하고 호출할 수 있다.
프로퍼티의 키만 확인하거나, 키에 들어있는 값만 확인하거나 선택할 수 있다.
⚠️
for..in
반복문은 프로퍼티 키가 심볼형이라면 확인할 수 없다.
for (key in object) {
// 각 프로퍼티의 키를 이용해서 본문을 수행합니다.
}
------------------------------------------------
let user = {
name: "John",
age: 30,
isAdmin: true
};
for (let key in user) { // key 라는 변수를 이용해서 user 객체의 내부를 조사한다.
alert(key); // 변수만 출력할 경우 user 객체의 모든 프로퍼티 키가 호출 된다.
alert(user[key]); // user 객체의 모든 프로퍼티 키에 저장된 값이 호출 된다.
}
/* */
(1)
for (let key in user) == (let key = user)
key 변수에는 user 객체를 참조할 수 있다.
즉, key를 호출하면 user 객체를 호출할 수 있음
(2)
alert(key)
user 객체를 호출한다. ( user 객체에 있는 프로퍼티 키가 호출 됩니다. )
(3)
alert(user[key])
user 객체에 프로퍼티 키를 호출합니다. ( 각 프로퍼티 키들의 값이 호출됩니다. )
/* */
제가 이해하고 있는 부분이 100% 맞다고 할 수 없습니다. 개인적인 견해로 작성한 해석이라
근본적인 동작원리는 조금 다를 수 있습니다. 어찌 됏든 결과 값은 동일하다는 것을 인지하시면
될 거 같습니다.
객체의 정렬 방식은 2가지가 있습니다.
차례대로 작성한 코드를 순서대로 정렬하는 방식과, 작성한 코드가 숫자형 정수라면 정수의
크기대로 정렬하는 정수 프로퍼티(integer property)가 있습니다.
let codes = {
"49": "독일",
"41": "스위스",
"44": "영국",
"1": "미국"
};
for (let key in codes) {
alert(key); // 1, 41, 44, 49 가 출력됩니다.
}
/* */
* 문자형들이 숫자형으로 형 변환되서, 정수 프로퍼티 규칙에 의해 숫자의 크기대로 출력된다.
* 다만, 소수점이나 문자열 앞에 + 단항 덧셈이 붙게 되면 정수 프로퍼티가 적용되지 않는다.
🔔 정수 프로퍼티 규칙
✔️ 자료형이 숫자형인 경우
프로퍼티의 작성 순서에 상관없이, 숫자의 크기대로 출력된다. ( 작은 수 부터 출력 )
✔️ 자료형이 문자형인 경우
자료형이 문자열인 경우에는, 정수로 형변환 할 수 있는 문자열들만 정수 프로퍼티로
인정 해줍니다. ( 예시 :'49'
'151'
등 )
⚠️ 예외 사항
소수점과, 문자열에 단항 덧셈 연산자가 붙은 경우에는 정수 프로퍼티가 아니다.
❓ 이유
정수 프로퍼티는, 값에 변동사항이 없어야 한다.
1) 형 변환 전과 이후의 값도 같아야 한다.
2) 소수점인 경우, 정수로 변환하면 원래의 숫자와 다르므로 정수 프로퍼티가 아니다.
쉽게 예를 들자면, 문자형에서+"49"
는 형 변환하면49
다. 문자열로 형 변환하면
"49"
가 된다. 원래의 값과 다르므로 정수 프로퍼티가 아니다.
소수점인 경우에는 기존의1.451
라는 값을 정수로 바꾸면1
이 됩니다. 원래의 값과
다르므로, 소수점 또한 정수 프로퍼티가 적용되지 않습니다.// 함수 Math.trunc는 소수점 아래를 버리고, 숫자의 정수부분만 반환한다. // 정프 : 정수프로퍼티 alert( String(Math.trunc(Number("49"))) ); // 출력 : 49, 기존에 입력한 값과 같으므로 정수프로퍼티 alert( String(Math.trunc(Number("+49"))) ); // 출력 : 49, 기존에 입력한 값과 다르므로 정프가 아님 alert( String(Math.trunc(Number("1.2"))) ); // 출력 : 1, 기존에 입력한 값과 다르므로 정프가 아님
let codes = {
"+49": "독일",
"+41": "스위스",
"+44": "영국",
"+1": "미국"
};
for (let key in codes) {
alert(key); // 49, 41, 44, 1이 출력 됩니다
}
/*
문자열 앞에 `+` 단항 연산자를 붙여서 숫자형으로 형변환 전과 이후의 값을 틀리게 만듭니다.
즉, 숫자형으로 형 변환하면 49지만, 문자열로 다시 형 변환하면 `49`가 되므로 기존의 값
+`49`와는 다릅니다. +가 생략되었죠. 이로 인해서 정수 프로퍼티라고 인정하지 않고 정렬방식
또한 코드의 작성흐름에 따라 순차적으로 정렬됩니다.
*/
객체는 몇 가지 특수한 기능을 가진 연관 배열(associative array)입니다.
객체는 프로퍼티(키와 값)을 저장합니다.
프로퍼티의 키는 문자열이나 심볼이여야 합니다.
프로퍼티의 값은 어떤 자료형이라도 상관 없습니다.
점 표기법 obj.key
, 대괄호 표기법 obj['key']
대괄호 표기법은 변수에 할당된 값을 키로 갖고올 수 있습니다 obj[string]
객체는 연산자와 같이 사용할 수 있습니다.
delete obj.key
: 프로퍼티를 삭제
'key' in obj
: obj 객체안에 key라는 프로퍼티 키가 있는지 유무 확인
for (let key in obj)
: obj 객체안의 모든 프로퍼티 키와 값을 확인
일반 객체 이외에도 다양한 종류의 객체가 있습니다.
Arrow
: 정렬된 데이터의 컬렉션을 저장할 때 사용
Date
: 날짜와 시간 정보를 저장할 때 쓰임
Error
: 에러 정보를 저장할 때 쓰임
등등.