Object

Happhee·2022년 4월 14일
1

AvenJS

목록 보기
3/17

자바스크립트에는 Boolean, Null, Undefined, Number, BigInt, String, Symbol, 객체 총 8개의 자료형이 있다. 앞의 7개는 단 하나의 데이터만 담을 수 있기에 원시형이라고 불리지만, 객체는 원시형과 달리 여러 개의 데이터를 담을 수 있다는 것이 특징이다.

독특한 자료형인 객체에 대해 알아보자.


✨ 객체

{ ... } 중괄호를 이용해 객체를 생성할 수 있다.
중괄호 안에는 key : value 쌍으로 구성된 property 여러 개의 정보 덩어리를 넣을 수 있다.

  • property
    key(이름) - value(값)의 쌍을 일컫는 말이며, ,로 구분할 수 있다.
  • key & value
    각각 property의 이름과 값을 정의한다.
    • key property의 이름이다.
      만약, 여러 단어를 조합하고 싶다면, key를 " "따옴표로 묶어주어야 한다.
    • value 어떤 자료형이든 넣을 수 있다.
      • 메서드
        value안에 들어간 함수를 말한다.

👇 다음은 빈 객체를 객체 생성자와 객체 리터럴로 만드는 예제 코드이다.

let person1 = new Object( );	// 객체 생성자 
let person2 = { };				// 객체 리터럴 

리터럴과 프로퍼티

중괄호를 이용해 객체를 선언하는 방법을 객체 리터럴이라고 한다.

중괄호 안에는 키 : 값쌍으로 구성된 프로퍼티가 들어간다.
:을 기준으로 왼쪽에는 키(프로퍼티 이름 또는 식별자)가 오고, 오른쪽에는 값이 위치한다.

👇 예제 코드로 살펴보자.

// 서히 객체 
let seohee = {
  // 키 : "hobby", 값 : "dance"
  hobby : "dance",
  // 키 : "age", 값 : 24
  age : 24
};

seohee 객체에는 두 개의 프로퍼티가 존재하는 것을 알 수 있다.

👇프로퍼티의 값을 가져오기 위해서는 점 표기법을 사용한다.

console.log(seohee.hobby);		// "dance"
console.log(seohee.age);		// 24

또한 프로퍼티 값에는 모든 자료형이 올 수 있다.

seohee.isWoman = true;

기존에 존재하는 객체에 점 표기법으로 프로퍼티를 추가하는 것도 가능하다.

  • 프로퍼티를 추가 / 삭제 / 이동을 용이하게 하기 위해서는 마지막 프로퍼티 끝을 쉼표(,)로 작성하면 좋으니 참고하길 바란다.

더불어 존재하던 프로퍼티나 이후에 추가한 프로퍼티 모두 delete연산자를 사용하여 프로퍼티를 삭제할 수 있다.

delete seohee.isWoman;

특이점

❗️ 프로퍼티의 이름으로 예약어가 가능 ❗️

변수 이름에서는 예약어가 사용되었지만, 객체 프로퍼티에는 제약이 없다.

let seohee = {
  for : 1,
  let : 2,
  return : 3,
};
console.log(seohee.for);		// 1
console.log(seohee.let);		// 2
console.log(seohee.return);		// 3

다만 __proto__ 접근자는 이름으로 사용할 수 없다. 이에 대한 내용은 뒤에서 다루자.

❗️ 상수 변수와 달리 상수 객체는 수정 가능 ❗️

const로 선언된 객체는 수정될 수 있다.

여기서 수정될 수 있다는 것은 상수 객체 내의 프로퍼티를 말하는 것이지 상수 객체 자체를 의미하는 것은 아니다.

👇 예제 코드로 살펴보자.

const seohee = {
  hobby : "dance",
  age : 24,
};
seohee.age = 12;	// 가능

seohee = {
  isWoman : true,
};					
// Uncaught SyntaxError: Identifier 'seohee' has already been declared

결과로 알 수 있듯이 seohee 상수 객체 내의 프로퍼티 age를 변경하는 것은 가능하지만, seohee 상수 객체에 또 다른 객체를 할당시키는 건 에러를 일으킨다.

대괄호 표기법

앞서 프로퍼티 이름으로 여러 개의 단어를 조합하고 싶을 때는 " "를 사용한다고 말했다.
하지만 이렇게 만들어진 프로퍼티에 점 표기법을 사용하여 접근한다면 값을 가져올 수 없을 것이다.

👇 예제 코드이다.

let seohee = {
  hobby : "dance",
  age : 24,
  "like strawberries" : true
};
console.log(seohee.like strawberries);
// Uncaught SyntaxError: missing ) after argument list

자바스크립트는 seohee.like까지만 인식하고 공백을 만나면서 문법 에러를 가져온다.

따라서 키에 자바스크립트가 이해할 수 없는 문자를 가진 경우에는 점 표기법이 아닌 대괄호 표기법 [ ]을 사용해야 한다.

let seohee = {
  hobby : "dance",
  age : 24,
  "like strawberries" : true
};
const key = "like strawberries";
console.log(seohee["like strawberries"]);	
// true
console.log(seohee[key]);	
// true
console.log(seohee.key);	
// undefined
console.log(seohee."like strawberries");
//Uncaught SyntaxError: Unexpected string

다만, 대괄호안에 사용될 키를 문자열로 만들어서 값을 가져온다면 이 또한 점 표기법에는 사용할 수 없다.

계산된 프로퍼티

객체의 프로퍼티 키가 대괄호로 표현되어 있을 경우에 이를 계산된 프로퍼티라고 한다.

👇 예제 코드를 살펴보자.

let fruit = prompt("어떤 과일을 가장 좋아합니까?", "strawberry");
let seohee = {
  [ fruit ] : 3,
};
console.log(seohee.strawberry);
  • 사용자가 strawberry를 입력한 경우

  • 사용자가 orange를 입력한 경우

이렇게 대괄호 표기법을 사용하면 프로퍼티의 이름의 제약을 없애주는 것이 장점이지만, 작성하기가 조금 번거롭다.
때문에 프로퍼티 이름이 확정된 상황이고 그것이 단순하다면 점 표기법을 사용하는 것을 권장하지만, 사용하다가 복잡한 상황이 다가온다면 대괄호 표기법으로 바꾸길 바란다.

단축 프로퍼티

실무에서 프로퍼티 값을 기존 변수에서 받아올 때 많이 사용하고, 이를 통해 프로퍼티의 이름과 값을 변수 이름과 똑같이 만든다.

👇 여태까지 객체를 만든 과정이다.

let seohee = {
  hobby : "dance",
  age : 24
};

하지만, 단축 프로퍼티를 이용하면 코드의 간결성을 유도할 수 있다.

let hobby;
let seohee = {
  hobby,
  age : 24
};
console.log(seohee);
// {hobby: undefined, age: 24}

✨ 객체 반복문

in 연산자

자바스크립트에서 객체는 존재하지 않는 프로퍼티에 접근해도 에러가 발생하지 않고, undefined를 반환한다. 이를 정확하게 검사하기 위해서 in 연산자 를 사용하여 프로퍼티 존재 여부를 확인한다.

👇 앞선 예제 코드에서 만든 seohee 객체에 대한 프로퍼티 존재 여부를 파악하는 코드이다.

const key = "hobby";

console.log("hobby" in seohee);		// true
console.log(key in seohee);			// true

console.log("age" in seohee);		// true
console.log("banana" in seohee);	// false

자료형을 배울 때, undefined변수가 정의되어 있지만, 값이 할당되지 않은 경우에 사용한다고 했다.
때문에, 객체안에 값으로 undefined를 할당하는 것은 지양하도록 해야 in 연산자를 올바르게 사용할 수 있다.

for ... in

객체의 모든 프로퍼티의 키를 순회하고 싶을 때 사용하는 반복문이다.

for (key in object){
  // 각 프로퍼티 키를 사용하여 반복문을 수행
}

👇 seohee객체를 for ... in 으로 순회해보자.

for(const key in seohee){
  console.log('키' , key);
  console.log('값' , seohee[key]);
}

키와 값을 차례대로 출력하게 된다.

키가 정수가 아니라면, 프로퍼티가 추가된 순서대로 객체를 순회하도록 되어있다.

하지만, 객체의 프로퍼티 키가 모두 숫자로 이루어져 있다면 자동 정렬되어 반복문을 수행한다.

let fruits = {
  "49": "orange",
  "41": "banana",
  "44": "apple",
  "1": "strawberry"
};

for (const fruitKey in fruits) {
  console.log(fruitKey);
}

1, 41, 44, 49의 순서대로 프로퍼티를 읽는다.


✨ 객체 복사

참조에 의한 객체 복사

객체를 변수에 저장하면, 값을 그대로 저장하는 것이 아니라 객체가 저장되어있는 메모리 주소에 대한 참조 값을 저장한다.

즉, 객체는 메모리 어딘가에 들어가 있고, 변수에는 객체를 참조할 수 있는 값이 저장된다는 것이다.

따라서 객체를 할당한 변수를 복사한다면, 객체가 복사되는 것이 아니라 객체의 참조값이 복사되는 것이다. 더불어 객체 비교할 때, =====은 동일하게 동작한다.

let seohee = { age : 12 };
let admin = seohee;

console.log( seohee == admin );	// true
console.log( seohee === admin );	// true

admin.age = 24;
console.log(seohee.age);	// 24
console.log(admin.age);		// 24

현재 seohee이 가리키는 주소와 admin이 가리키는 주소가 같기 때문에 둘 중 하나에서 프로퍼티의 값을 변경하면 함께 값이 변경된다.

하지만, 두 개의 객체를 빈 객체로 따로 생성할 경우, 모양은 같아도 주소 값이 다르다.

let object1 = { };
let object2 = { };

console.log( object1 === object2);	// false

복사, 병합과 Object.assgin

🤔 그렇다면 동일한 객체를 생성하면서 독립적으로 만들고 싶다면 어떻게 해야 할까?

새로운 객체를 만들고 기존 객체의 프로퍼티를 순회하면서 원시 수준까지의 프로퍼티를 복사해오면 된다.

let seohee = { 
  hobby : "dance",
  age : 24
};
let cloneSeohee = {};
for(const key in seohee){
  cloneSeohee[key] = seohee[key];
}
console.log(cloneSeohee);		// {hobby: 'dance', age: 24}

이렇게 독립적으로 객체를 만들면, 아래의 코드로 생성된 객체의 프로퍼티 값을 바꿔도 기존 객체의 프로퍼티의 값은 변경되지 않는다.

여러 개의 객체를 하나로 병합하기 위해서는 Object.assign을 사용하기도 한다.

let user = { name: "John" };

let permissions1 = { canView: true };
let permissions2 = { canEdit: true };

// permissions1과 permissions2의 프로퍼티를 user로 복사합니다.
Object.assign(user, permissions1, permissions2);

// now user = { name: "John", canView: true, canEdit: true }

또한, 반복문 없이도 간단하게 객체를 복사 할 수 있다.

let seohee = { 
  hobby : "dance",
  age : 24
};
let cloneSeohee = Object.assign({}, seohee);

중첩 객체 복사

중첩 객체로 이루어진 경우 지금까지 살펴본 방식으로는 중첩인 부분까지 모두 독립된 객체를 생성할 수 없다.

👇 중첩 객체를 복사해보자.

let seohee = { 
  hobby : "dance",
  age : 24,
  strawberry : {
    quantity : 3,
    color : "red"
  }
};
let cloneSeohee = Object.assign({ }, seohee);

// 중첩이 아닌 프로퍼티 값 변경
seohee.age = 42;
// 중첩 프로퍼티 값 변경
seohee.strawberry.quantity = 300;

console.log(seohee, cloneSeohee);

원본 객체의 나이와 딸기 갯수를 수정했을 때, 나이는 독립적으로 값이 변경되지만, 딸기의 객체는 동시에 변경됨을 알 수 있다.

이는 깊은 복사가 진행되지 못했기 때문이다.
👇 중첩 복사를 완벽하게 독립적으로 진행하기 위해서는 반복문을 사용하는 것이 필요하다.

let cloneSeohee = {};

for(const key in seohee){
  if(typeof(seohee[key]) === "object"){
    cloneSeohee[key] = {};
    for(const key2 in seohee[key]){
      cloneSeohee[key][key2] = seohee[key][key2];
    }
  } else {
    cloneSeohee[key] = seohee[key];
  }
}

독립적인 객체로 생성됨을 알 수 있다.


🌈 결론

객체의 프로퍼티에는 여러 개의 자료형이 올 수 있기 때문에, 이를 적절하게 활용한다면 개발자만의 객체를 생성하여 의도하는 대로 코드를 동작하게 구현할 수 있을 것이다. 또한 여러 단계의 복사 중 원하는 깊이 만큼의 복사를 진행하여 동적으로 값을 변경할 수 도 있기에 이를 활용하는 방법을 정확하게 아는 것이 필요해보인다.


📚 학습할 때, 참고한 자료 📚

profile
즐기면서 정확하게 나아가는 웹프론트엔드 개발자 https://happhee-dev.tistory.com/ 로 이전하였습니다

0개의 댓글