객체 - 기본

devheyrin·2022년 4월 20일
0

modern javascript

목록 보기
19/26

자바스크립트에는 여덟 가지 자료형이 있다. 이 중 일곱 개는 오직 하나의 데이터만을 담을 수 있는 ‘원시형'이다.

객체형은 원시형과 달리 다양한 데이터를 담을 수 있다. 키로 구분된 데이터 집합이나 복잡한 개체를 저장할 수 있다. 객체는 자바스크립트 거의 모든 면에 녹아있는 개념이므로 자바스크립트를 잘 다루려면 객체를 잘 이해하고 있어야 한다.

객체는 중괄호를 이용해 만들 수 있다. 중괄호 안에는 키:값 쌍으로 구성된 프로퍼티를 여러 개 넣을 수 있는데, 키로는 문자형, 값으로는 모든 자료형이 허용된다. 프로퍼티 키는 프로퍼티 이름이라고 부르기도 한다.

서랍장을 상상하면 객체를 이해하기 쉽다. 서랍장 안에 든 파일을 프로퍼티, 파일 각각에 붙어있는 이름표는 객체의 키라고 생각하면 된다. 복잡한 서랍장 안에서 이름표가 있으면 원하는 파일을 쉽게 찾을 수 있듯이, 객체에서는 키를 사용해 프로퍼티를 쉽게 찾을 수 있다. 추가나 삭제도 쉽게 할 수 있다.

빈 객체를 만드는 방법은 두 개가 있다.

let user = new Object(); // '객체 생성자' 문법
let user = {};  // '객체 리터럴' 문법

중괄호를 이용해 객체를 선언하는 것을 객체 리터럴이라 하며, 객체 선언 시 주로 선언하는 방법이다.

리터럴과 프로퍼티

중괄호 안에는 키:값 쌍으로 구성된 프로퍼티가 들어간다.

let user = {     // 객체
  name: "John",  // 키: "name",  값: "John"
  age: 30        // 키: "age", 값: 30
};

프로퍼티 키는 프로퍼티 이름, 식별자 라고도 한다.

객체 user에는 두 개의 프로퍼티가 있다.

  • name (이름), “John”(값)
  • age (이름), 30(값)

서랍장(객체) 안에 파일 두개(프로퍼티 두 개)가 담겨 있는데, 각 파일에 “name”, “age” 라는 이름표가 붙어있다고 생각하면 쉽다.

점 표기법으로 프로퍼티 값을 읽을 수도 있다.

// 프로퍼티 값 얻기
alert( user.name ); // John
alert( user.age ); // 30

서랍장에 파일을 넣고 뺄 수 있듯, 프로퍼티를 추가하고 삭제할 수 있다.

user.isAdmin = true;

delete 연산자를 사용해 프로퍼티를 삭제할 수 있다.

delete user.age;

프로퍼티 이름에 공백이 포함된 경우 따옴표로 묶어 준다.

let user = {
  name: "John",
  age: 30,
  "likes birds": true  // 복수의 단어는 따옴표로 묶어야 합니다.
};

마지막 프로퍼티에 쉼표를 붙여 끝낼 수 있는데, 이런 쉼표를 ‘trailing(길게 늘어지는)’ 혹은 ‘hanging(매달리는)’ 쉼표라고 한다. 끝에 쉼표를 붙이면 모든 프로퍼티가 유사한 형태를 보이므로 프로퍼티를 추가, 삭제, 이동하기 쉬워진다.

대괄호 표기법

여러 단어를 조합해 프로퍼티 키를 만든 경우, 점 표기법을 사용해 값을 읽어올 수 없다.

// 불가능한 방법 
user.likes birds = true 

점 표기법은 유효한 변수 식별자인 경우, 즉 공백이 없고 숫자로 시작하지 않으며 $, _ 외의 특수문자가 없어야 사용 가능하다.

점 표기법을 사용할 수 없는 경우 ‘대괄호 표기법' 을 사용하면 된다.

let user = {};

// set
user["likes birds"] = true;

// get
alert(user["likes birds"]); // true

// delete
delete user["likes birds"];

다음과 같이 변수를 키로 사용하는 것도 가능해진다.

let key = "likes birds";

user[key] = true;

변수를 사용해서 사용자 입력값 변경 등에 따라 key 를 바꿔줄 수 있다.

let user = {
  name: "John",
  age: 30
};

let key = prompt("사용자의 어떤 정보를 얻고 싶으신가요?", "name");

// 변수로 접근
alert( user[key] ); 
// 프롬프트 창에 "name"을 입력한 경우 John 리턴
// "age" 입력한 경우 30 리턴

점 표기법으로는 이러한 방식을 이용할 수 없다.

let user = {
  name: "John",
  age: 30
};

let key = "name";
alert( user.key ) // undefined

계산된 프로퍼티

객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우, 이를 계산된 프로퍼티라고 한다.

let fruit = prompt("어떤 과일을 구매하시겠습니까?", "apple");

let bag = {
  [fruit]: 5, // 변수 fruit에서 프로퍼티 이름을 동적으로 받아 옵니다.
};

alert( bag.apple ); // fruit에 "apple"이 할당되었다면, 5가 출력됩니다.

위 예시에서 bag 객체의 프로퍼티 키 [fruit] 는 프로퍼티 키를 변수 fruit 에서 가져오겠다는 것을 의미한다.

사용자가 apple 을 입력하면 bag 에는 {apple:5} 가 할당된다.

대괄호 안에는 복잡한 표현식이 올 수도 있다.

let fruit = 'apple';
let bag = {
  [fruit + 'Computers']: 5 // bag.appleComputers = 5
};

대괄호 표현법은 프로퍼티 키와 값의 제약을 없애주기 때문에 점 표기법보다 강력하지만, 작성하기가 번거롭다는 단점이 있다. 따라서 프로퍼티 이름이 확정된 상황이고 단순한 이름이라면 점 표기법을 사용하다가, 복잡한 상황이 발생하면 대괄호 표기법으로 바꾸는 경우가 많다.

단축 프로퍼티

실무에서는 프로퍼티 값을 기존 변수에서 받아와 사용하는 경우가 종종 있다.

function makeUser(name, age) {
  return {
    name: name,
    age: age,
    // ...등등
  };
}

let user = makeUser("John", 30);
alert(user.name); // John

위 코드에서 프로퍼티들은 이름과 변수의 값이 변수의 이름과 동일하다. 이런 경우 프로퍼티 값 단축 구문을 사용하면 코드를 짧게 줄일 수 있다.

function makeUser(name, age) {
  return {
    name, // name: name 과 같음
    age,  // age: age 와 같음
    // ...
  };
}

한 객체에서 일반 프로퍼티와 단축 프로퍼티를 같이 사용할 수도 있다.

let user = {
  name,  // name: name 과 같음
  age: 30
};

프로퍼티 이름의 제약사항

객체 프로퍼티 이름으로 for, let, return 등 예약어를 사용할 수 있다.

문자형이나 심볼형이 아닌 값은 문자열로 자동 형 변환된다.

let obj = {
  0: "test" // "0": "test"와 동일합니다.
};

// 숫자 0은 문자열 "0"으로 변환되기 때문에 두 얼럿 창은 같은 프로퍼티에 접근
alert( obj["0"] ); // test
alert( obj[0] ); // test (동일한 프로퍼티)

단, 특별 대우를 받는 이름이 하나 있는데, __proto__ 이다.

let obj = {};
obj.__proto__ = 5; // 숫자를 할당합니다.
alert(obj.__proto__); // [object Object] - 숫자를 할당했지만 값은 객체가 된다. 

__proto__ 의 프로퍼티 값으로 원시값 5를 할당했지만 무시되었다. 더 자세한 내용은 추후에 알아보기로 하자!

in 연산자로 프로퍼티 존재 여부 확인하기

자바스크립트 객체의 중요 특징 중 하나는 존재하지 않는 프로퍼티에 접근하려 해도 에러가 발생하지 않고, undefined 를 반환한다는 것이다.

let user = {};

alert( user.noSuchProperty === undefined ); 
// true는 '해당 프로퍼티가 존재하지 않음'을 의미 

in 연산자를 사용해 프로퍼티 존재 여부를 확인할 수 있다.

"key" in object
let user = { name: "John", age: 30 };

alert( "age" in user ); // user.age가 존재하므로 true
alert( "blabla" in user ); // user.blabla는 존재하지 않기 때문에 false

프로퍼티 이름은 보통 따옴표로 감싼 문자열이다. 따옴표를 생략하면 엉뚱한 변수가 조사 대상이 된다.

let user = { age: 30 };

let key = "age";
alert( key in user ); 
// true, 변수 key에 저장된 값("age")을 사용해 프로퍼티 존재 여부를 확인

in 연산자는 프로퍼티 값으로 undefined 가 할당되어있는 경우 존재여부를 정확히 판별할 수 있다.

let obj = {
  test: undefined
};

alert( obj.test ); 
// test라는 이름의 프로퍼티가 존재하지만 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력

alert( "test" in obj ); 
// true 가 출력된다. `in`을 사용하면 프로퍼티 유무를 제대로 확인 가능 

한편, 값을 알 수 없거나 비어있다는 것을 나타낼 때에는 undefined 대신 null 을 주로 사용한다.

for ... in 반복문

for in 반복문을 사용하면 객체의 모든 키를 순회할 수 있다.

for (key in object) {
  // 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행합니다.
}

아래 예시를 사용하면 객체의 모든 프로퍼티가 출력된다.

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
}

49, 41, 44, 1 의 순서대로 객체에 추가했기 때문에 49가 가장 먼저 출력될 것 같지만, 1이 첫 번째로 출력된다!

키가 정수여서 프로퍼티가 자동 정렬되었기 때문이다.

💡 정수 프로퍼티란?
정수 프로퍼티란 정수로 바꿔도 결과가 기존과 일치하는 문자열을 말한다. +49 와 1.2는 정수로 변환하면 기존의 문자열과 달라지기 때문에 정수 프로퍼티가 아니다.

자동 정렬을 피하려면 다음과 같이 + 를 붙여주면 된다.

let codes = {
  "+49": "독일",
  "+41": "스위스",
  "+44": "영국",
  // ..,
  "+1": "미국"
};

for (let code in codes) {
  alert( +code ); // 49, 41, 44, 1 - 숫자형으로 다시 바꾸어 출력하므로 + 가 사라진다. 
}
profile
개발자 헤이린

0개의 댓글