본문 바로가기

데일리

[23.10.17] 객체 리터럴

글의 목적

  • layered architecture로 express 서버를 만들던 중 그냥 만들면 MVC에서 뎁스하나만 추가하여 계층만 나눈것이기 때문에, 했던거 또 하느니 class로 dependency injection을 하면서 만들었는데 객체에 대한 이해도가 부족한것 같아서 이참에 제대로 공부하려고 함.

본론

1. 객체 리터럴

1.1 객체란?

  • js는 객체 기반의 프로그래밍 언어이다.
  • js를 구성하는 거의 모든 것, 원시값을 제외한 나머지가 모두 객체이다.
  • 객체는 0개 이상의 프로퍼티로 구성된 집합이며, 프로퍼티는 key와 value으로 구성된다.
  • js에서 사용할 수 있는 모든 값은 프로퍼티가 될 수 있다.
  • 프로퍼티 값이 함수일 경우, 일반 함수와 구분하기 위해 method라 부른다. (함수와 메서드는 다르다.)
  • 다시 정의하면 객체는 프로퍼티와 메서드로 구성된 집합체이다.
    • 프로퍼티 : 객체의 상태를 나타내는 값(data)
    • 메서드 : 프로퍼티(상태 데이터)를 참조하고 조작할 수 있는 동작(behavior)

1.2 객체 리터럴에 의한 객체 생성

  • js는 프로토타입 기반 객체지향 언어로서 클래스 기반 객체지향 언어와는 달리 다양한 객체 생성 방법을 지원함.
    • 객체 리터럴
    • Object 생성자 함수
    • 생성자 함수
    • Object.create 메서드
    • class(ES6)
  • 리터럴이란 약속된 문자로 값을 생성하는 표기법이고 중괄호{} 문자는 객체로 약속된 표기법이다.
const obj = {
  name: test,
  sayHi: () => {
    console.log(`Hi!, My name is ${this.name}.`);
  },
};
  • 객체 리터럴의 중괄호는 코드 블록을 의미하지 않는다.

1.3 프로퍼티

  • 객체는 프로퍼티의 집합이며, 프로퍼티는 키와 값으로 구성된다.
  • 프로퍼티 키는 빈 문자열을 포함하는 모든 문자열 또는 심벌 값을 사용할 수 있다.
  • 프로퍼티 값은 js에서 사용할 수 있는 모든 값을 사용할 수 있다.
  • 프로퍼티 키는 식별자로 사용되지만 식별자 네이밍 규칙을 따를 필요는 없다. 단 그럴경우 반드시 따옴표로 묶어줘야 한다.
const person = {
  name: 'test',                      // 식별자 네이밍 규칙 준수
  'phone-number': '010-####-####'    // 식별자 네이밍 규칙 미준수
}
  • 대괄호([...])로 묶으면 문자열 또는 문자열로 평가할 수 있는 표현식을 사용해 프로퍼티를 생성할 수도 있다.
const sayHi = {};
const key = "say";
sayHi[key] = "hi";
console.log(sayHi); // { say: 'hi' }
  • 빈 문자열도 프로퍼티 키로 사용할 수 있다 (권장하진 않는다.)
const test = {
  "": "",
};
console.log(test); // { '': '' }
  • 문자열이나 심벌 값 대신 다른 값을 사용한다면 암묵적으로 타입변환을 통해 문자열로 변환된다.
const test = {
  1: 1,
  2: 2,
};
// 따옴표가 붙진 않지만 내부적으로는 문자열이다. (이젠 붙는다. 야호!!)
console.log(test); // { '1': 1, '2': 2 } 
  • 예약어를 프로퍼티 키로 사용해도 에러가 발생하지 않는다. (권장하진 않는다.)
const test = {
  function: "",
  const: "",
};
console.log(test); // { function: '', const: '' }
  • 중복 선언된 프로퍼티 키는 후자가 에러가 발생하지 않고 전자를 덮어쓴다.
const test = {
  name: "test",
  name: "not error",
};
console.log(test); // { name: 'not error' }

1.4 프로퍼티 접근

  • 프로퍼티에 접근하는 방법은 두가지가 있다.
    • 마침표 표기법 : 객체.프로퍼티 키
    • 대괄호 표기법 : 객체['프로퍼티 키']
  • 대괄호 표기법의 프로퍼티 키는 반드시 따옴표로 감싸야한다. (따옴표가 없으면 식별자로 해석)
  • 객체에 존재하지 않는 프로퍼티 키에 접근하면 에러가 발생하지 않고 undefined를 반환한다.
  • 프로퍼티 키가 숫자나 네이밍 규칙에 부합하는 경우 대괄호 표기법만 가능하고 숫자의 경우 따옴표가 없어도 된다.
const test = {
  name: "test",
  1: "number",
};
console.log(test.name);           // test
console.log(test["name"]);        // test
console.log(test.age);            // undefined
console.log(test.1); // error
console.log(test.'1'); // error
console.log(test[1]);             // number
console.log(test["1"]);           // number

1.5 프로퍼티 값 갱신

  • 이미 존재하는 프로퍼티에 값을 할당하면 값이 갱신된다.
const test = {
  name: "test",
};
test.name = "TEST";
console.log(test.name); // TEST

1.6 프로퍼티 동적 생성

  • 존재하지 않는 프로퍼티에 값을 할당하면 프로퍼티가 추가되며 값이 할당된다.
const test = {
  name: "test",
};
test.age = "20";
console.log(test); // { name: 'test', age: '20' }

1.7 프로퍼티 삭제

  • delete 연산자는 객체의 프로퍼티를 삭제할 수 있다.
  • 존재하지 않는 프로퍼티를 delete로 삭제하려고 하면 에러가 발생하지 않고 무시된다.
const test = {
  name: "test",
};
test.age = "20";
console.log(test); // { name: 'test', age: '20' }
delete test.age;
console.log(test); // { name: 'test' }
delete test.address;
console.log(test); // { name: 'test' }

1.8 프로퍼티 축약

  • 프로퍼티의 키와 값이 동일하다면(이것은 정확하게 프로퍼티 키와 프로퍼티의 값이 변수의 할당된 값, 즉 식별자 표현식과 동일하다면) 축약이 가능하다. 이때 프로퍼티 키는 변수 이름으로 자동 생성된다.
const a = 1;
const b = 2;

const test = {
  a: a,
  b: b,
};
const test2 = {
  a,
  b,
};
console.log(test); // { a: 1, b: 2 }
console.log(test2); // { a: 1, b: 2 }

1.9 계산된 프로퍼티 키의 동적 생성

  • 대괄호 표기법을 활용하여 계산식을 넣어 프로퍼티키를 동적으로 생성할 수 있다.
  • 내부에서 넣든 외부에서 넣든 상관없다.
const prop = "프로퍼티";
let i = 0;
const obj = {
  [`${prop}-${++i}`]: i,
  [`${prop}-${++i}`]: i,
  [`${prop}-${++i}`]: i,
};
obj[prop + "-" + ++i] = i;
obj[prop + "-" + ++i] = i;
obj[prop + "-" + ++i] = i;
obj[`${prop}-${++i}`] = i;
obj[`${prop}-${++i}`] = i;
obj[`${prop}-${++i}`] = i;

console.log(obj);
/* {
  '프로퍼티-1': 1,
  '프로퍼티-2': 2,
  '프로퍼티-3': 3,
  '프로퍼티-4': 4,
  '프로퍼티-5': 5,
  '프로퍼티-6': 6,
  '프로퍼티-7': 7,
  '프로퍼티-8': 8,
  '프로퍼티-9': 9
} */

1.10 정확한 객체에 메서드 정의

  • 정확하게 메서드를 정의하고 싶다면 프로퍼티 키에 function키워드나 arrow function으로 메서드를 정의해서는 안된다.
  • 메서드란 오직 축약 표현으로 정의된 함수만을 의미한다.
const obj = {
  x: 1,
  method() {                      // 메서드
    return this.x;
  },
  function: function () {         // 메서드아님
    return this.x;
  },
  arrow: () => {                  // 메서드아님
    return this.x;
  },
};
console.log(obj.method());        // 1
console.log(obj.function());      // 1
console.log(obj.arrow());         // undefined
console.log(new obj.method());    // TypeError: obj.method is not a constructor
console.log(new obj.function());  // function {}
console.log(new obj.arrow());     // TypeError: obj.arrow is not a constructor
  • 메서드가 가진 아름다움
const parent = {
  name: "mom",
  sayHi() {
    return `Hi! ${this.name}`;
  },
};
const son = {
  __proto__: parent,
  sayHi() {
    return `${super.sayHi()}. How are you doing?`;
  },
};
console.log(son.sayHi()); // Hi! Mom. How are you doing?

결론

  • 글이 생각보다 길어져서 시리즈로 분할하려고 한다.
  • 객체는 시작도 안했고 객체 리터럴로 할 수 있는 것들만 일단은 정리했다.