객체

찬찬잉·2022년 3월 10일
0
post-thumbnail

객체

자바스크립트에는 여덟 가지의 자료형이있습니다.

  • 숫자형 - 정수, 부동 소수점 숫자 등의 숫자를 나타낼 때 사용합니다.
  • 문자형 - 빈 문자열이나 글자들로 이뤄진 문자열을 나타낼 때 사용합니다.
  • 불린형 - true, false를 나타낼 때 사용합니다.
  • 객체형 - 복잡한 데이터 구조를 표현할 때 사용합니다.
  • 심볼형 - 객체의 고유 식별자를 만들 때 사용합니다.
  • null - null 값만을 위한 독립 자료형입니다. null은 알 수 없는 값을 나타냅니다.
  • undefined - 값만을 위한 독립 자료형입니다. undefined는 할당되지 않은 값을 나타냅니다.
  • bigint - 길이나 제약 없이 정수를 나타낼 수 있습니다.

이 중 일곱 개는 오직 하나의 데이터 (문자열, 숫자 등)만 담을 수 있어 원시형(primitive type)이라 부릅니다.
그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있습니다. 키로 구분된 데이터 딥합이나 복잡한 개체(entity)를 저장할 수 있죠.

객체는 중괄호{...}를 이용해서 만들 수 있습니다. 중괄호 안에는 키(key): 값(value) 쌍으로 구성된 프로퍼티(property)를 여러 개 넣을 수 있는데, 엔 문자형, 엔 모든 자료형이 허용됩니다.
프로퍼티 키는 프로퍼티 이름이라고도 부릅니다.

서랍장을 상상하면 객체를 이해하기 쉽습니다.
서랍장 안 파일은 프로퍼티, 파일 각각에 붙어있는 이름표는 객체의 키라고 생각하시면 됩니다.
복잡한 서랍장 안에서 이름표를 보고 원하는 파일을 쉽게 찾을 수 있듯이, 객체에선 키를 이용해 프로퍼티를 쉽게 찾을 수 있습니다. 추가나 삭제도 마찬가지입니다.

빈 객체(빈 서랍장)를 만드는 방법은 두 가지가 있습니다.

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

중괄호 {...}를 이용해 객체를 선언하는 것을 객체 리터럴(obeject literal)이라고 부릅니다. 객체를 선언할 땐 주로 이 방법을 사용합니다.

리터럴과 프로퍼티

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

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

콜론(:)을 기준으로 왼쪽엔 키가, 오른쪽엔 값이 위치합니다.
프로퍼티 이름 혹은 식별자라고도 부릅니다.
객체 user에는 프로퍼티가 두 개 있습니다.

  • 첫 번째 프로퍼티 - name(이름)과 John(값)
  • 두 번째 프로퍼티 - age(이름)과 30(값)

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

서랍장에 파일을 추가하고 뺄 수 있듯이 개발자는 프로퍼티를 추가, 삭제할 수 있습니다.
점 표기법(dot notation)을 이용하면 프로퍼티 값을 읽는 것도 가능합니다.

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

프로퍼티 값엔 모든 자료형이 올 수 있습니다. 불린형 프로퍼티를 추가해봅시다.

  user.admin = true;


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

  delete user.age;


여러 단어를 조합해 프로퍼티 이름을 만든 경우엔 프로퍼티 이름을 "따옴표("", '')"로 묶어줘야 합니다.

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

마지막으로 프로퍼티 끝은 쉼표(,)로 끝날 수 있습니다.

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

이런 쉼표를 trailing(길게 늘어지는)혹은 hanging(매달리는) 쉼표라고 부릅니다. 이렇게 끝에 쉼표를 붙이면 모든 프로퍼티가 유사한 형태를 보이기 때문에 프로퍼티를 추가, 삭제, 이동하는게 쉬워집니다.

상수 객체는 수정될 수 있습니다.

  • 주의!!! const로 선언 된 객체는 수정될 수 있습니다.
  const user = {
    name: "John"
  };

  user.name = "Pete"; // (*)

  alert(user.name); // Pete

(*)로 표시한 줄에서 오류를 일으키는 것처럼 보일 수 있지만 그렇지 않습니다.
constuser의 값을 고정하지만, 그 내용은 고정하지 않습니다.
constuser=...를 전체적으로 설정하려고 할 때만 오류가 발생합니다.

대괄호 표기법

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

  // 문법 에러가 발생합니다.
  user.likes birds = true	

자바스크립트는 위와 같은 코드를 이해하지 못합니다. user.likes까지는 이해하다가 예상치 못한 birds를 만나면 문법 에러를 뱉어냅니다.
은 키가 유효한 변수 식별자인 경우에만 사용할 수 있습니다.
유효한 변수 식별자엔 공백이 없어야합니다. 또한 숫자로 시작하지 않아야하며 $_를 제외한 특수 문자가 없어야합니다.

키가 유요한 변수 식별자가 아닌 경우엔 점 표기법 대신에 대괄호 표기법이라 불리는 방법을 사용할 수 있습니다. 대괄호 표기법은 키에 어떤 문자열이 있던지 상관없이 동작합니다.

  let user = {};

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

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

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

이제 문법 에러가 발생하지 않죠, 대괄호 표기법 안에서 문자열을 사용할 땐 문자열을 따옴표로 엮어줘야합니다.

대괄호 표기법을 사용하면 아래 예시에서 변수를 키로 사용한 것과 같이 문자열뿐만 아니라 모든 표현식의 평가 결과를 프로퍼티 키로 사용할 수 있습니다.

  let key = "likes birds";

  // user["likes birds"] = true; 와 같습니다.
  user[key] = true;

변수 key는 런타임에 평가되기 때문에 사용자 입력값 변경 등에 따라 값이 변경될 수 있습니다. 어떤 경우든, 평가가 끝난 이후의 결과가 프로퍼티 키로 사용됩니다.

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

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

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

그런데 점 표기법은 이런 방식이 불가능합니다.

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

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

계산된 프로퍼티

객체를 만들 때 객체 리터럴 안의 프로퍼티 키가 대괄호로 둘러싸여 있는 경우, 이를 게산된 프로퍼티(computed property)라고 부릅니다.

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

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

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

위 에시에서 [fruit]는 프로퍼티 이름을 변수 fruit에서 가져오겠다는 것을 의미합니다. 사용자가 프롬프트 대화상자에 apple을 입력했다면 bag{apple: 5}가 할당되었을 겁니다.

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

  // 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
  bag[fruit] = 5;

두 방식 중 계산된 프로퍼티를 사용한 예시가 더 깔끔해 보이네요.

단축 프로퍼티

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

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

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

위 예시의 프로퍼티들은 이름과 값이 변수의 이름과 동일하네요, 이렇게 변수를 사용해 프로퍼티를 만드는 경우는 아주 흔한데, 프로퍼티 값 단축 구문(property value shorthand)을 사용하면 코드를 짧게 줄일 수 있습니다.
name:name대신 name만 적어주어도 프로퍼티를 설정할 수 있죠

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

한 객체에서 일반 프로퍼티와 단축 프로퍼티를 함께 사용하는 것도 가능합니다.

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

프로퍼티 이름의 제약사항

아시다시피 변수 이름(키)엔 for, let, return같은 예약어를 사용하면 안됩니다.
그런데 객체 프로퍼티엔 이런 제약이 없습니다.

  // 예약어를 키로 사용해도 괜찮습니다.
  let obj = {
    for: 1,
    let: 2,
    return: 3
  };

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

이와 같이 프로퍼티 이름엔 특별한 제약이 없습니다. 어떤 문자형, 심볼형 값도 프로퍼티 키가 될 수 있죠

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

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

이런 특징을 응용하면 프로퍼티 존재 여부를 쉽게 확인할 수 있습니다.

  let user = {};

  alert( user.noSuchProperty === undefined ); 

  // true는 '프로퍼티가 존재하지 않음'을 의미합니다.

이렇게 undefined와 비교하는 것 이외에도 연산자 in을 사용하면 프로퍼티 존재 여부를 확인할 수 있습니다.

문법은 다음과 같습니다.

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

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

in 왼쪽엔 반드시 프로퍼티 이름이 와야 합니다. 프로퍼티 이름은 보통 따옴표로 감싼 문자열입니다.
따옴표를 생략하면 아래와 같이 엉뚱한 변수가 조사 대상이 됩니다.

  let user = { age: 30 };

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

그런데 이쯤 되면 "undefined 랑 비교해도 충분한데 왜 in연산자가 있는 거지?"라는 의문이 들 수 있습니다.

대부분의 경우, 일치 연산자를 사용해서 프로퍼티 존재 여부를 알아내는 방법 (=== undefined)은 꽤 잘 동작합니다. 그런데 가끔은 이 방법이 실패할 때도 있습니다. 이럴 때 in을 사용하면 프로퍼티 존재 여부를 제대로 판별할 수 있습니다.

프로퍼티는 존재하는데, 값에 undefined를 할당한 경우

  let obj = {
    test: undefined
  };

  alert( obj.test ); // 값이 `undefined`이므로, 얼럿 창엔 undefined가 출력됩니다. 그런데 프로퍼티 test는 존재합니다.

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

obj.test는 실제 존재하는 프로퍼티입니다. 따라서 in연산자는 정상적으로 true를 반환합니다.
undefined는 변수는 정의되어 있으나 값이 할당되지 않은 경우에 쓰기 때문에 프로퍼티 값이 undefiend인 경우는 흔치않습니다.

for...in 반복문

for...in 반복문을 사용하면 객체의 모든 키를 순회할 수 있습니다.
for..in은 앞서 학습했던 for(;;)반복문과는 완전히 다릅니다.

  for (key in object) {
    // 각 프로퍼티 키(key)를 이용하여 본문(body)을 실행합니다.
  }
  let user = {
    name: "John",
    age: 30,
    isAdmin: true
  };

  for (let key in user) {
    // 키
    alert( key );  // name, age, isAdmin
    // 키에 해당하는 값
    alert( user[key] ); // John, 30, true
  }

for..in 반복문에서도 for(;;)문 처럼 반복 변수(looping variable)를 선언(let key)했다는 점에 주목해 주시길 바랍니다.
반복 변수명은 자유롭게 정할 수 있습니다. for(let prop in obj)같이 key말고 다른 변수명을 사용해도 괜찮습니다.

profile
디자이너, 기획자 출신의 개발자

0개의 댓글