JS-객체로 작업하기

p-q·2023년 1월 27일
0

JavaScript는 간단한 객체 기반 패러다임 위에 만들어졌습니다. Object(객체)는 Properties(속성)의 컬렉션이고, property는 이름('키')과 값 사이의 연결관계입니다. 속성의 값이 함수인 경우에는 메서드라고 부릅니다. 브라우저 안에 미리 정의된 객체 뿐만 아니라 직접 객체를 정의할 수도 있습니다.

객체개요

JavaScript에서의 객체는 다른 프로그래밍 언어에서와 마찬가지로 현실 세계에서의 객체(사물)라고 부르는 것과 비교할 수 있습니다.
JavaScript에서 객체의 개념은 현실에서 인식 가능한 사물로 이해가 가능합니다.

JavaScript에서 객체는 속성과 타입을 가진 독립적인 개체(entity)입니다. 현실의 컵과 비교해본다면, 컵은 색, 디자인, 무게, 소재 등의 속성을 가진 객체라고 할 수 있습니다. 마찬가지로 JavaScript 객체 역시 특징을 결정짓는 속성을 가질 수 있습니다.

객체와 속성

JavaScript 객체는 자신과 연관된 속성들을 가집니다. 객체의 속성은 객체에 붙은 변수라고 설명할 수 있겠습니다. 객체의 속성은 일반적인 JavaScript 변수와 똑같은데, 다만 객체에 붙어있다는 점만 다릅니다. 속성에 접근할 떈 간단한 마침표 표기법을 사용합니다.

objectName.propertyName

다른 모든 JavaScript 변수와 마찬가지로, 객체의 이름과 속성의 이름 모두 대소문자를 구분합니다. 객체에 속성을 정의하려면 값을 할당합니다.
예를들어 myCar라는 객체를 생성하고, make,model,year라는 속성을 추가해보겠습니다.

const myCar = new Object();
myCar.make = 'Kia';
myCar.model = 'K7';
myCar.year = 2011;

//객체 리터럴 방식으로 추가
const myCar = {
  make: 'Kia',
  model: 'K7',
  year: 2011
};

//객체에 할당되지 않은 속성은 null이아니며 undefined 입니다.
console.log(myCar.color); => undefined

객체 속성은 대괄호 표기법을 사용해 접근할 수도 있습니다. 객체를 때때로 연관배열(associative array)이라고도 부르기도 하는데, 속성은 자신에 접근할 수 있는 문자열 값과 연관되어 있기 때문입니다.

myCar['make'] = 'Kia';

객체 속성 이름은 유효한 문자열 혹은 문자열로 변환 가능한 것이면 모두 가능하며, 빈 문자열도 여기 포함됩니다. 그러나 유효한 식별자가 아닌 이름(공백, 붙임표, 숫자로 시작하는 이름)을 가진 속성은 대괄호 표기법으로만 접근할 수 있습니다.
대괄호 표기법은 속성 이름이 동적으로 정해지는 경우, 즉 런타임 시점까지 알 수 없는 경우 유용합니다.

// 네 개의 변수를 쉼표로 구분해서
// 한 번에 생성하고 할당
const myObj = new Object(),
      str = 'myString',
      rand = Math.random(),
      obj = new Object();

myObj.type              = '마침표 구문';
myObj['date created']   = '공백을 포함한 문자열';
myObj[str]              = '문자열 값';
myObj[rand]             = '무작위 수';
myObj[obj]              = '객체';
myObj['']               = '빈 문자열까지';

console.log(myObj);

모든 대괄호 표기법 안의 키는 심볼이 아닌경우 문자열로 변환됩니다, 객체의 속성 키는 문자열이나 심볼 뿐이기 때문입니다.

속성 접근은 변수에 저장된 문자열 값으로도 가능합니다.

let propertyName = 'make';
myCar[propertyName] = 'Ford';

propertyName = 'model'
myCar[propertyName] = 'Mustang';

//대괄호 표기법은 for...in 과 함께 객체의 열거 가능한 속성을 순회할 때도 사용가능합니다.
function showProps(obj, objName) {
  let result = '';
  for (let i in obj) {
    // obj.hasOwnProperty()를 사용해서 객체의 프로토타입 체인에 존재하지 않는 속성을 제외
    if (obj.hasOwnProperty(i)) {
      result += `${objName}.${i} = ${obj[i]}\n`;
    }
  }
  console.log(result);
}

showProps(myCar, 'myCar')
//Result
myCar.make = Ford
myCar.model = Mustang
myCar.year = 1969

객체속성 나열하기

  • for...in 반복문 이 방법은 객체와 객체의 프로토타입 체인에 존재하는 모든 열거 가능한 속성을 순회합니다. 모든 프로퍼티를 순회하는 방법입니다.
  • Object.keys(o) 이 방법은 o객체 자신만의(프로토타입 체인을 제외한) 열거 가능한 속성 키를 배열로 반환합니다.
  • Object.getOwnPropertyNames(o) 이 방법은 o객체 자신만의 모든(열거불가능한 포함) 속성 키를 배열로 반환합니다.

프로토타입 체인 상의 속성 중, 같은 이름의 속성이 체인에서 앞서 존재해 가려진 경우 나열하는 방법

function listAllProperties(o) {
  let objectToInspect = o;
  let result = [];

  while(objectToInspect !== null) {
    result = result.concat(Object.getOwnPropertyNames(objectToInspect));
    objectToInspect = Object.getPrototypeOf(objectToInspect)
  }

  return result;
}

객체 생성하기

객체 생성에는 객체초기자(new Object(), Object.create(), 객체리터럴) 또는 생성자함수를 정의 후 new 연산자와 함께 호출해서 객체 인스턴스를 생성할 수 있습니다.

객체 초기자

리터럴 표기에 의한 객체 생성

const obj = {
  property_1: value_1, 
  2: value_2,
  ...,
  'propery n': value_3
  // 속성의 값은 식별자,숫자,문자열일 수도 있습니다.
}

위 코드에서 obj 는 새로운 객체의 이름이고 콜론 앞에 위치한 속성 이름은 식별자, 각각 value는 속성 이름에 할당할 표현식입니다. obj와 할당 구문은 선택 사항으로, 이 객체를 다른 곳에서 참조하지 않아도 되면 변수에 할당할 필요도 없습니다.

객체 초기자는 표현식이며 자신이 속한 선언문이 실행될 때마다 새로운 객체를 생성합니다. 같은 초기자가 생성한 객체끼리도 구별 가능하며 서로 비교했을때 거짓을 반환합니다. 초기자가 생성하는 객체는 마치 new Object()를 호출한 것과 같이 생성됩니다. 즉 객체 초기자 표현식의 결과 객체들은 Object의 인스턴스입니다.

//cond가 참일 때만 객체를 생성해서 변수 x에 할당합니다.
let x;
if (cond) {
  x = {greeting: '안녕하세요'};
}

//myHonda를 세 개의 속성과 함께 생성합니다. engine 속성 역시 자신만의 속성을 가진 객체입니다.
const myHonda = {color: 'red', wheels: 4, engine: {cylinders: 4, size: 2.2}};

//객체 초기자로 배열을 생성할 수도 있습니다. 배열리터럴
let coffees = ['French Roast', 'Colombian', 'Kona'];

생성자 함수

생성자 함수를 작성하여 객체 타입을 정의하고(생성자 함수 작성시 객체 타입의 첫글자는 대문자로 시작하는 관례가 있습니다.) new 연산자를 사용해 객체 인스턴스를 생성합니다.

function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}

const myCar = new Car('Kia', 'K7', 2011);

myCar를 생성한 후 매개변수로 지정한 값을 속성에 할당합니다.
new를 사용한 호출로 Car 생성자 함수를 이용해 여러개의 객체를 만들 수 있습니다.

//속성 접근하기
myCar.make.name; // => 'Kia'
//속성 추가하기
myCar.color = 'red';
myCar.color.name; // => 'red'

Object.create() 메서드

Object.create() 메서드로 객체를 생성할 수도 있습니다. 이 메서드는 생성자 함수 없이도 생성할 객체의 프로토타입을 지정할 수 있습니다.

상속

모든 객체는 적어도 하나의 다른 객체를 상속합니다. 상속 대상 객체를 프로토타입이라고 부르며, 상속한 속성은 생성자의 prototype 객체에서 찾을 수 있습니다. 상속과 프로토타입 체인

객체 속성 인덱싱

객체의 속성에 접글할 땐 속성 이름이나 인덱스로 접근할 수 있습니다. 처음에 속성을 이름으로 정의했으면 그 속성은 항상 이름으로만 접근해야하며 인덱스로 정의했다면 인덱스로만 접근해야 합니다.

메서드 정의

objectName.methodName = functionName;

const obj = {
  myMethod: function(params) {
  //...
  }
  //축약방식 사용시 js가 최적화를 도와줌
  myOtherMethod(params) {
  //...
  }  
}

//메소드 호출
obj.myMethod(params);

this를 통한 객체참조

this를 사용하면 메서드 내에서 현재 객체를 참조할 수 있습니다.

const Manager = {
  name: "John",
  age: 27,
  job: "소프트웨어 엔지니어"
}
const Intern = {
  name: "Ben",
  age: 21,
  job: "소프트웨어 엔지니어 인턴"
}

function sayHi() {
  console.log(`안녕하세요, 제 이름은 ${this.name}입니다.`)
}

// 두 객체 모두에 sayHi 함수 추가
Manager.sayHi = sayHi;
Intern.sayHi = sayHi;

Manager.sayHi(); // 안녕하세요, 제 이름은 John 입니다.'
Intern.sayHi(); // 안녕하세요, 제 이름은 Ben 입니다.'
//위의 this는 자신이 속한 객체를 참조합니다.

getter and setter

getter(접근자)는 특정 속성의 값을 반환하는 메서드입니다. setter(설정자)는 특정 속성의 값을 설정하는 메서드입니다.

///객체 초기자를 사용해 접근자와 설정자를 정의
const obj = {
  a: 7,
  get b() {
    return this.a + 1;
  },
  set c(x) {
    this.a = x / 2;
  }
};

console.log(obj.a); // 7
console.log(obj.b); // 8 <-- 이 시점에 get b() 메서드 실행
obj.c = 50;         //   <-- 이 시점에 set c(x) 메서드 실행
console.log(obj.a); // 25

// Object.defineProperties() 메서드로 추가

const obj = { a: 0 };

Object.defineProperties(obj, {
    'b': { get: function() { return this.a + 1; } },
    'c': { set: function(x) { this.a = x / 2; } }
});

obj.c = 10; // 설정자 실행, a 속성에 10 / 2 = 5 할당
console.log(obj.b); // 접근자 실행, a + 1 = 6 반환

속성삭제

상속한 속성이 아닌 경우 delete 연산자로 속성 삭제가 가능합니다.

// a와 b 두 속성의 새로운 객체 생성
const myobj = new Object();
myobj.a = 5;
myobj.b = 12;

// a 속성을 제거해서 b 속성만 남김
delete myobj.a;
console.log ('a' in myobj); // 출력: false

객체비교

객체는 참조 타입이며, 두 개의 객체는 서로 같은 속성을 같더라도 절대 같지 않으며 오직 자기 자신과의 비교만 참을 반환합니다

// 두 개의 변수, 두 개의 같은 속성을 가진 서로 다른 객체
const fruit = {name: '사과'};
const fruitbear = {name: '사과'};

fruit == fruitbear; // false 반환
fruit === fruitbear; // false 반환

// 두 개의 변수, 하나의 객체
const fruit = {name: '사과'};
const fruitbear = fruit;  // fruit 객체 참조를 fruitbear에 할당

// fruit과 fruitbear가 같은 객체를 가리킴
fruit == fruitbear; // true 반환
fruit === fruitbear; // true 반환

fruit.name = '포도';
console.log(fruitbear); // 출력: { name: "사과" }가 아니라 { name: "포도" }
profile
ppppqqqq

0개의 댓글