JS. 객체

MJ·2022년 9월 3일
0

Java Script

목록 보기
31/57
post-thumbnail

1. 객체

  • JS 에는 8가지의 자료형 타입이 있고, 이중 객체를 제외한 7개의 자료형은 오직 하나의
    데이터 (문자열,숫자형 등)만 담을 수 있어 원시형(primitive type)이라고 부릅니다.

  • 그런데 객체형은 원시형과 다르게 다양한 자료형을 저장할 수 있습니다.

  • 키로 구분된 데이터의 집합이나 복잡한 객체(entity)를 저장할 수 있습니다.

객체의 필요성

배열을 사용하기엔 알맞지 않는 요소를 생성할 때 사용합니다.

예를 들면 한식이라는 카테고리에 음식명, 칼로리, 지방, 단백질등등 여러가지 데이터에
대한 값이 필요할 때, 키와 쌍으로 연결지어서 구분하면 편리합니다.

배열로 사용한다면 어떤 주제에 대한 값인지 분명하게 확인하기 어렵기 때문입니다.


1.1 객체 구조

  • 객체는 { } 중괄호를 사용해 만들고, { } 안에는 객체를 구성하는 프로퍼티가 존재합니다.
    프로퍼티는 키와 값으로 이루어져 있습니다.

  • 키는 프로퍼티를 가르키는 이름표이고, 문자열이나 심볼형을 사용합니다.

  • 값은 데이터를 할당할 수 있고 객체를 포함한 모든 자료형이 허용 됩니다.

🔔 객체(object), 프로퍼티(property), 키(key), 값(value)


서랍장을 상상해서 객체 이해하기

서랍장안에는 무수한 파일들이 있습니다. 파일을 찾으려면 이름표를 확인해서 손쉽게
파일을 찾을 수 있습니다. 객체도 마찬가지로, 객체안에 수많은 프로퍼티들이 있습니다.
원하는 프로퍼티만을 찾고 싶을 때는, 프로퍼티에 붙은 키를 이용해서 손쉽게 프로퍼티를
찾을 수 있습니다.


서랍장 = 객체
파일들 = 프로퍼티
이름표 = 프로퍼티의 키



1.2 객체 생성하는 2가지 방법

  • 객체 생성 방법에는 new 연산자를 사용하는 방법과, 리터럴 방식이 있습니다.
❤️ 객체 생성 방법

let user = new object();	// 생성자 함수를 사용해서 객체 생성
let user = {};				// 리터럴 방식으로 객체 생성


/* */
new object();
1) new 연자를 사용해서 object() 함수를 호출함 > new 연산자가 붙은 함수는 생성자 함수가 된다
2) 생성자 함수는 내부에서 this라는 객체가 생성된다.


{};	
1) { } 중괄호를 사용해서 객체를 생성하는 방법은, 객체 리터럴 방식이라고 한다.
2) 생성자 함수를 사용하지 않고 사용 가능



1.3 객체 리터럴 방식

  • { } 중괄호를 사용해서 객체를 만드는 방식을 객체 리터럴 방식이라고 합니다.

  • 객체는 프로퍼티 키와 값으로 구성되어 있습니다.

  • 프로퍼티는 .점 표기법과 []대괄호 표기법으로 접근할 수 있습니다.

let user = {		// 객체 리터럴 방식으로 선언
  name: "John", 	// 키 : name | 값 : "John"
  age: 30			// 키 : age | 값 : 30
};


/* */
콜론(:)을 기준으로, 좌측에는 키가 우측에는 값이 들어갑니다.
프로퍼티의 키는 프로퍼티의 이름 또는 식별자라고 말합니다.

위에서 user 객체를 이미지로 표시해보면 아래와 같습니다.

user 라는 객체에 2개의 프로퍼티가 있고, 각 프로퍼티의 키(이름표)는
nameage 입니다. 프로퍼티의 값을 확인 하려면, 프로퍼티의 키를 호출하면 됩니다.

// 프로퍼티 값 얻기
alert( user.name ); // user 객체의 name 프로퍼티 안에 있는 값 : John
alert( user.age ); //  ...~ 값 : 30

1.4 표기법으로 프로퍼티 생성

  • 프로퍼티는 객체 밖에서도 .표기법이나 []대괄호 표기법으로 프로퍼티를 생성할 수 있다.
user.isAdmin = true;	// user 객체에 isAdmin 프로퍼티 키를 생성, 값으로는 true을 할당


/* */
프로퍼티의 값에는 논리형 뿐만 아니라 모든 자료형이 올 수 있습니다.


1.5 delete 연산자로 프로퍼티 삭제

delete user.age;	// user 객체의 age 프로퍼티가 삭제 됩니다.


/* */
delete 연산자를 사용하면 객체의 프로퍼티를 삭제할 수 있습니다.


1.6 프로퍼티의 키의 이름이 여러 개 일 떄

  • 프로퍼티를 구성하는 요소 중 키의 문자열이 여러 단어로 구성되어 있을 떄는 " 따옴표를
    사용해서 단어를 묶어줘야 합니다.
let user = {
  name: "John",
  age: 30,
  "true boolean": true	// 복수의 단어는 " " 따옴표로 묶어줍니다.
};

1.7 프로퍼티 간의 구분

  • 객체안에 여러 개의 프로퍼티가 존재할 수 있는데, 프로퍼티 마다 ,쉼표를 통해서 구분
    해줘야 합니다.

  • 객체의 마지막 프로퍼티는 ,을 사용하지 않아도 됩니다.

let user = {
  name: "John",
  age: 30,	// (*)
};


/* */
(*)
프로퍼티 간의 구분은 쉼표로 구분 짓습니다. 이런 쉼표를 trailing(길게 늘어지는) 혹은 
hanging(매달리는) 쉼표라고 부릅니다. 객체의 마지막 프로퍼티에는 쉼표를 붙여도 되고
붙이지 않아도 됩니다.



상수 객체

  • 상수는 변하지 않는 값을 뜻합니다. 객체를 변수가 아닌 상수로도 생성할 수 있는데,
    상수로된 객체는 객체명은 바꿀 수 없지만, 내부의 프로퍼티는 수정할 수 있습니다.
const user = {			// user 라는 객체명은 상수기에 변경할 수 없다.
  name: "John"
};

user.name = "Pete";		// 상수인 객체도 프로퍼티는 변경할 수 있다.

alert(user.name);		// 출력 : Pete


/* */
1) 상수로 선언된 객체명 `user`는 변경할 수 없다.
2) 하지만 객체안의 프로퍼티는 상수여도 변경할 수 있다.



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

🔔 . 표기법과 [] 대괄호 표기법

. 표기법은 키의 이름이 유효한 변수 식별자인 경우에만 접근할 수 있습니다.
즉, 공백이 있어선 안되고 숫자로 시작하지 말아야하며 특수문자는 $와 _만 허용합니다.


[] 대괄호 표기법은 키에 어떤 문자열이나 공백이 있던지 상관없이 접근할 수 있다.


2.1 대괄호 표기법 사용하기

  • 대괄호 표기법은 따옴표가 있어도 접근할 수 있습니다.

  • 대괄호 표기법으로 프로퍼티를 생성 할 때는, 키의 이름은 " 따옴표로 묶어줘야 합니다.
    ( 따옴표의 종류는 상관 없습니다 )

❤️ 대괄호 표기법 프로퍼티 생성 

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'];

2.2 변수를 프로퍼티의 키로 사용하기

  • 대괄호 표기법의 장점은, 일반 변수의 값을 객체의 프로퍼티 키로 사용할 수 있습니다.
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 출력


/* */
대괄호 표기법을 사용하면 변수 뿐만 아니라 모든 표현식의 결과 값을 
프로퍼티의 키로 사용할 수 있습니다.

2.3 표현식의 값을 프로퍼티 키로 사용하기

  • 변수 뿐만 아니라 모든 표현식의 결과를 프로퍼티의 키로 사용할 수 있습니다.

  • 사용자로부터 값을 입력받고, 그 값을 변수에 저장하는 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 라는 프로퍼티를 참조하므로 오류가 발생한다.


2.4 계산된 프로퍼티

  • 객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우
    이를 계산된 프로퍼티
    (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


❗ 사용자가 입력한 값을 변수를 통해서 동적으로 받아오는 것은 대괄호 표기법만 가능하다.

2.5 대괄호 표기법으로 여러 개의 표현식 사용

  • 이미 생성된 변수와, 문자열을 병합해서 프로퍼티를 생성할 수 있습니다.
let fruit = 'apple';
let bag = {
  [fruit + 'Computers']: 5 // 이 프로퍼티 키는 'appleComputers' 이 된다.
};	


/* */
대괄호 표기법은 프로퍼티의 키와 값에 제약을 없애주기 때문에 점 표기법보다 훨씬 강력합니다.
다만 작성하기가 어렵다는 단점이 있습니다.

🔔 점 표기법과 대괄호 표기법

프로퍼티의 이름이 확정된 상황이라면 점 표기법을 사용하고, 복잡한 상황이 생긴다면
대괄호 표기법으로 변경해서 사용하는 경우가 이상적입니다.



3. 단축 프로퍼티

  • 프로퍼티의 값을 기존 변수에서 받아와 사용하는 경우를 살펴보겠습니다.
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

3.1 일반 프로퍼티와 단축프로퍼티 같이 사용

  • 하나의 객체에서 일반 프로퍼티와 단축 프로퍼티를 같이 사용할 수 있다.
let d = {
 name,		// name: name과 같다.
 age : 30
};



4. 프로퍼티 이름의 제약 사항

  • 일반적으로 변수의 이름에는 예약어를 사용하면 안됩니다. (let, return, for 등)

  • 프로퍼티를 사용하면 키를 정의할 때 제약 사항이 없습니다.

let obj = {
  for: 1,
  let: 2,
  return: 3
};

alert( obj.for + obj.let + obj.return );	// 출력 : 6


/* */
프로퍼티의 키 이름에는 아무런 제약사항이 없습니다.
어떤 문자형이나 심볼형도 키의 이름으로 사용할 수 있습니다.

문자형이나 심볼형에 속하지 않는 자료형은 문자열로 자동 형 변환됩니다.
만약 키의 이름에 숫자 0을 넣으면 문자형 '0' 으로 형변환 됩니다.

4.1 프로퍼티 키 이름 형 변환

  • 객체에서 프로퍼티를 생성할 때 키의 이름은 문자형이나 심볼형으로 사용해야 한다.

  • 다른 자료형이 온다면 됩니다.

let obj = { 
 0: "test" 		// 자료형이 숫자형이기에 문자형으로 형 변환 된다. ( "0": "test"와 동일 )
};

alert( obj[0] );	// "test" 출력, 정수 0을 문자열 '0'으로 변경해서 프로퍼티 키를 찾는다.
alert( obj['0'] );	// "test" 출력 

4.2 __proto__ ?

  • 프로퍼티의 이름에는 제약사항이 없으나, __proto__ 라고 정의하게 되면 객체가 할당된다.
let obj = {};

obj.__proto__ = 5;

alert(obj.__proto__);	// 출력 : object Obejct, 숫자를 할당 했지만 객체가 되었습니다.


/* */
역사적인 이유로 특별대우 받는 이름이 __proto__ 입니다.
이 문제는 추후 포스팅에에서 다뤄보겠습니다..



5. 프로퍼티의 존재 유무 확인하기

  • JS 객체의 중요한 특징 중 하나는 다른 언어와는 다르게 존재하지 않는 프로퍼티에
    접근하려 해도 오류 대신에 undefined를 반환
    한다는 것 입니다.

  • 이러한 특징을 사용해서 프로퍼티가 존재하는지 유무를 확인할 수 있습니다.

let user = {};

alert( user.noSuchProperty === undefined ); 
// true : 프로퍼티가 존재하지 않음을 의미합니다.
// 해당 프로퍼티의 이름이(키) 존재한다면 false가 나오겠죠.

5.1 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

5.2 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' 라는 프로퍼티가 있는지 검사하므로 오류가 발생



6. for..in 반복문

  • 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% 맞다고 할 수 없습니다. 개인적인 견해로 작성한 해석이라
근본적인 동작원리는 조금 다를 수 있습니다. 어찌 됏든 결과 값은 동일하다는 것을 인지하시면
될 거 같습니다.



7. 객체 정렬 방식

  • 객체의 정렬 방식은 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, 기존에 입력한 값과 다르므로 정프가 아님

7.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 : 에러 정보를 저장할 때 쓰임
등등.

profile
프론트엔드 개발자가 되기 위한 학습 과정을 정리하는 블로그

0개의 댓글