surf core js : 객체

Dino_·2021년 7월 26일
0

surf javascript

목록 보기
11/28
post-thumbnail

객체

자바스크립트엔 여덟 가지 자료형이 있다. (숫자형, 문자형, 불린, bigint, object, symbol, null, undefined)

이 중 일곱 개는 오직 하나의 데이터(문자열, 숫자 등)만 담을 수 있어 '원시형(primitive type)'이라 부른다.

그런데 객체형은 원시형과 달리 다양한 데이터를 담을 수 있다. 키로 구분된 데이터 집합이나 복잡한 개체(entity)를 저장할 수 있다.

객체는 자바스크립트 거의 모든 면에 녹아있는 개념이므로 자바스크립트를 잘 다루려면 객체를 잘 이해하고 있어야 한다.

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

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

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

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

리터럴과 프로퍼티

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

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

'콜론(:)'을 기준으로 왼쪽엔 키가, 오른쪽엔 값이 위치한다.

프로퍼티 키는 프로퍼티 ‘이름’ 혹은 '식별자’라고도 부른다.

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

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

점 표기법(dot notation)을 이용하면 프로퍼티 값을 읽는 것도 가능하다.

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

서랍장에 파일을 추가하고 뺄 수 있듯이 개발자는 프로퍼티를 추가, 삭제할 수 있다. 불린형 프로퍼티를 추가해보자.

user.isAdmin = 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

(*)로 표시한 줄에서 오류를 일으키는 것처럼 보일 수 있지만 그렇지 않다.

const는 user의 값을 고정하지만, 그 내용은 고정하지 않는다.

const는 user=...를 전체적으로 설정하려고 할 때만 오류가 발생한다.

상수 객체 프로퍼티를 만드는 또 다른 방법이 있다. 이후에 프로퍼티 플래그와 설명자를 공부할 때 포스팅하도록 하겠다.

대괄호 표기법

띄어쓰기를 포함한 프로퍼티 키를 만든 경우엔, 점 표기법을 사용해 프로퍼티 값을 읽을 수 없다(문법적으로).

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

'점’은 키가 '유효한 변수 식별자’인 경우에만 사용할 수 있다.

유효한 변수 식별자엔 공백이 없어야 합니다. 또한 숫자로 시작하지 않아야 하며 $와 _를 제외한 특수 문자가 없어야 한다.

변수 명명 규칙 포스트에서 언급했었다.

키가 유효한 변수 식별자가 아닌 경우엔 점 표기법 대신에 '대괄호 표기법(square bracket notation)'이라 불리는 방법을 사용할 수 있다.

대괄호 표기법은 키에 어떤 문자열이 있던지 상관없이 동작한다.

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는 런타임에 평가되기 때문에 사용자 입력값 변경 등에 따라 값이 변경될 수 있다. 아래의 computed assignment와 같은 원리이다.

어떤 경우든, 평가가 끝난 이후의 결과가 프로퍼티 키로 사용된다. 이를 응용하면 코드를 유연하게 작성할 수 있다.

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

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

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

// 점 표기법은 불가능
alert( user.key ) // undefined

계산된 프로퍼티(computed property)

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

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

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


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

위 예시에서 [fruit]는 프로퍼티 이름을 변수 fruit에서 가져오겠다는 것을 의미한다.

아래 예시는 위 예시와 동일하게 동작한다.

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

// 변수 fruit을 사용해 프로퍼티 이름을 만들었습니다.
bag[fruit] = 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

변수를 사용해 프로퍼티를 만드는 경우는 아주 흔한데, 프로퍼티 값 단축 구문(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

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

문자형이나 심볼형에 속하지 않은 값은 문자열로 자동 형 변환된다.

키에 숫자 0을 넣으면 문자열 "0"으로 자동변환된다.

let obj = {
  0: "test" // "0": "test"와 동일
};

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

이와같이 객체 프로퍼티 키에 쓸 수 있는 문자열엔 제약이 없지만, 역사적인 이유 때문에 특별 대우를 받는 이름이 하나 있는데, proto이다.

추후 공부한 후에 작성할 예정이다.

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

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

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

let user = {};

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

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

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

alert( "age" in user ); // true
alert( "blabla" in user ); // false

in 왼쪽엔 반드시 프로퍼티 이름이 와야 한다. 프로퍼티 이름은 보통 따옴표로 감싼 문자열이다.

대부분의 경우, 일치 연산자를 사용해서 프로퍼티 존재 여부를 알아내는 방법("=== undefined")은 (문법적으로 장난질하지 않는 이상) 잘 동작한다.

‘for…in’ 반복문

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

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

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

반복 변수명(let key)은 자유롭게 정할 수 있다.

객체 정렬 방식

객체는 '특별한 방식으로 정렬’된다.

정수 프로퍼티(integer property)는 자동으로 정렬되고, 그 외의 프로퍼티는 객체에 추가한 순서 그대로 정렬된다.

아래 객체엔 국제전화 나라 번호가 담겨있다.

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

for (let code in codes) {
  alert(code); // 1, 41, 44, 49
}

현재 개발 중인 애플리케이션의 주 사용자가 독일인이라라면 나라 번호를 선택하는 화면에서 49가 맨 앞에 오도록 하는 게 좋다.

그런데 코드를 실행해 보면 예상과는 전혀 다른 결과가 출력된다.

이유는 나라 번호(키)가 정수이어서 1, 41, 44, 49 순으로 프로퍼티가 자동 정렬되었기 때문이다.

'정수 프로퍼티’라는 용어는 변형 없이 정수에서 왔다 갔다 할 수 있는 문자열을 의미한다.

문자열 "49"는 정수로 변환하거나 변환한 정수를 다시 문자열로 바꿔도 변형이 없기 때문에 정수 프로퍼티이다. 하지만 '+49’와 '1.2’는 정수 프로퍼티가 아니다.

한편, 키가 정수가 아닌 경우엔 작성된 순서대로 프로퍼티가 나열된다.

let user = {
  name: "John",
  surname: "Smith"
};
user.age = 25; // 프로퍼티를 하나 추가합니다.

// 정수 프로퍼티가 아닌 프로퍼티는 추가된 순서대로 나열됩니다.
for (let prop in user) {
  alert( prop ); // name, surname, age
}

위 예시에서 49(독일 나라 번호)를 가장 위에 출력되도록 하려면 나라 번호 앞에 "+"를 붙여 정수 프로퍼티가 적용되지 못하도록 하게 하면 된다.

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

for (let code in codes) {
  alert( +code ); // 49, 41, 44, 1
}

Reference

profile
호기심 많은 청년

0개의 댓글