🎁

[JS] 객체(Object)


객체

객체 타입의 값은 여러 프로퍼티(property)의 모음이다. 숫자, 문자열 등 다양한 값을 하나로 묶어서 표현할 수 있게 된다.

1let obj = {
2 name: "웅재",
3 age: 24,
4 "like beer": true
5}

중괄호 안에 콤마로 구분된 프로퍼티 목록이 있다. 각 프로퍼티에는 이름이 있고 다음으로 콜론(:)과 값이 이어진다. 프로퍼티의 이름이 사용 가능한 이름이 아니면 따옴표로 묶어야 한다.

프로퍼티의 이름에는 예약어를 사용하지 않아야 된다는 등 같은 제약이 없다. for, if 같은 것을 프로퍼티 이름으로 해도 괜찮다. 문자형이나 심볼형에 속하지 않은 값은 문자열로 자동변환된다.

객체를 만들 때, 괄호 안의 프로퍼티 이름이 대괄호로 둘러싸여 있는 경우, 이를 'computed property'라고 부른다.

1let student = prompt("어떤 학생을 넣을까요?", "머규");
2let room = {
3 [student]: "공부하는중...",
4};
5console.log(room["머규"]);
6// -> 공부하는중...

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

프로퍼티

자바스크립트에서 거의 모든 값(null과 undefined 제외)은 프로퍼티를 가지고 있다. var s = "Hello"라고 변수를 선언한 후 s.length를 사용하면 s 문자열의 길이를 얻을 수 있다.

프로퍼티에 접근할 수 있는 방법에는 두 가지가 있다. 점 표가법과 대괄호 표기법을 사용하는 것이다. 방금 예에서 사용한 방식이 점을 사용한 것이다. 대괄호를 사용해서 length 프로퍼티에 접근하려면, s["length"]로 할 수 있다.

메서드(method)는 함수를 포함한 프로퍼티를 말한다. 아까 예제에서 선언한 변수 s의 메서드 s.toUpperCase()를 호출하면 해당 문자열의 모든 문자가 대문자로 변환된다.

= 연산자를 사용해서 프로퍼티 표현식에 값을 할당할 수 있다. 프로퍼티 값이 이미 존재하면 대체하고, 그렇지 않다면 새 프로퍼티를 바인딩한다. delete 연산자를 사용하면 프로퍼티를 제거할 수도 있다.

1let example = { left: 1 , right: 2 };
2delete example.left;
3console.log(example.left);
4// -> undefined
5console.log("left" in example);
6// -> false

개체 프로퍼티를 확인하려면 Object.keys 함수를 사용하면 된다.

1console.log(Object.keys({ x: 0, y: 0, z: 2 }));
2// -> ["x", "y", "z"]

Object.assign을 사용해서 한 객체의 모든 프로퍼티를 다른 객체로 복사할 수 있다.

1let a = { a: 1, b: 2 };
2Object.assign(a, { b: 3, c: 4 });
3console.log(a);
4// -> {a: 1, b: 3, c: 4}

옵셔널 체이닝

?.은 앞의 평가 대상이 undefinednull이면 평가를 멈추고 undefined를 반환한다. 어떤 유저가 주소 정보가 있는지 없는지 알 수 없는 상태에서 주소에 접근할 때, 옵셔널 체이닝을 사용하면 안전하게 접근할 수 있다.

1let user = {};
2// console.log(user && user.address && user.address.street);
3console.log(user?.address?.street);
4// -> undefined

메서드와 대괄호 프로퍼티 표기에도 사용가능하다.

Mutability

자바스크립트의 모든 원시 타입(primitive data type)변경 불가능한(immutable) 값이다.

  • Boolean
  • Number
  • Bigint
  • String
  • null
  • undefined
  • Symbol

"엥? 변경할 수 있잖아?"라고 할 수도 있겠다. 아래 코드를 보자.

1var text = "a";
2text = "b";

첫 줄이 실행되면 "a"라는 값이 생성되고 text는 메모리에 생성된 문자열 "a"를 가리킨다. 두 번째 줄이 실행되면 "b"라는 값이 생성되고 text"b"를 가리킨다. 따라서, 값 자체를 변경하는게 아닌 새로운 값을 가리키게 되는 것이다.

원시 타입 이외의 모든 값은 객체 타입을 가지며 변경 가능한(mutable) 값이다. 위 예에서 봤듯이 객체는 새로운 값을 생성할 필요없이 직접 변경이 가능하다.

1var user = {
2 name: '정',
3 address: {
4 city: '대구'
5 }
6};
7
8var myName = user.name;
9
10user.name = '김';
11console.log(myName); // -> 정
12
13myName = user.name;
14console.log(myName); // -> 김

위 코드에서 user.name의 값을 변경했지만 myName의 값은 변경되지 않는다. myNameuser.name을 할당하면, user.name의 참조가 할당되는게 아니라 변경 불가능한 값 이 새로 생성되고 이것을 참조하게 되기 때문이다.

객체의 복사

객체와 원시 타입의 근본적인 차이중 하나는 객체는 '참조에 의해(by reference)' 저장되고 복사된다는 것이다.

객체 변수에는 객체가 그대로 저장되는 것이 아니라, 객체가 저장되어 있는 메모리 주소인 객체에 대한 참조 값이 저장된다. 따라서, 객체가 할당된 변수를 복사할 땐 객체의 참조 값이 복사된다.

1let student = { name: "머규" };
2let teacher = student;
3teacher.name = "탁"
4console.log(student);
5// -> 탁
6console.log(student === teacher);
7// -> true

객체 자체를 복사하고 싶다면 Object.assign 메서드를 사용하거나, for..in을 사용해서 새로운 빈 객체에 프로퍼티를 하나하나 복사해 넣어주면 된다. for..in은 객체의 모든 프로퍼티를 순회한다.

1Object.assign(dest, [src1, src2, src3...])

dest가 목표로 하는 객체고, src는 복사하고자 하는 개체다. src1, ..., srcN의 프로퍼티를 dest에 복사해준다.

이것보다 더 쉬운 방법은 스프레드 문법 ...을 사용하는 것이다. 스프레드 문법은 iterable 객체를 인수/프로퍼티 목록으로 확장해준다. 아래와 같이 사용할 수 있다.

1let arr = [1, 2, 3];
2let clone = [...arr];
3// let clone = Object.assign([], arr); 와 같은 효과를 볼 수 있다.

만약 복사하고 싶은 객체의 모든 프로퍼티가 원시값이 아니라면? 프로퍼티 하나하나를 검사하면서, 그 값이 객체인 경우 객체의 구조도 복사해주는 반복문을 사용해야한다. 이런 방식을 'deep cloning'이라고 한다.

JSON

프로퍼티는 값을 가지고 있다기 보다는 값을 가리키고 있다. 만약 내가 이 데이터들을 파일에 저장하거나 다른 컴퓨터로 보낼때는 어떻게 해야할까? 그러기 위해서는 데이터를 전송할 수 있는 형식으로 변환해야 한다. 이때 필요한 것이 serialization(직렬화)이다. 직렬화를 통해 내 메모리 어딘가 흩어져있는 프로퍼티들을 모아 연속적인 데이터로 변환하는 것이다.

자바스크립트에서 많이 사용되는 직렬화 형식이 JSON(JavaScript Object Notation)이다. 웹에서 데이터를 저장하고 통신하는 형식으로도 널리 사용된다.

작성 방법은 객체를 작성하는 것과 비슷하다. 차이점은 모든 프로퍼티 이름을 큰 따옴표로 묶어야 하며 함수 호출, 변수, 실제 계산과 관련된 모든 것은 허용되지 않고 단순 데이터 표현식만 허용된다.

1{
2 "name": "웅재",
3 "alive": true
4}

자바스크립트에서 제공하는 JSON.stringifyJSON.parse 함수를 사용해서 데이터를 JSON 형식으로 변환하거나 다시 JSON에서 데이터로 변환할 수 있다.

참조:
Eloquent JavaScript
ko.javascript.info