본문 바로가기

Backend/Javascript

[Javascript] - Object

Object (객체)

 

- 자바스크립트는 null 과 undefined 를 제와한 모든 것을 객체로 취급합니다.

 

- 객체는 자바스크립트의 기본 데이터 구조입니다.

 

객체는 속성을 갖고 있으며, 각 속성에는 이름과 값이 있습니다. 이름은 문자열이고 값은 어떤 자료형이든 될 수 있습니다.

 

- 객체 리터럴을 사용해 새로운 객체를 만들 수 있습니다.

 

- 객체 리터럴의 범위는 중괄호 ({}) 로 결정됩니다. 괄호 안쪽에 0개 이상의 속성을 콤마로 구분하여 나열 가능합니다.

 

let bar = 'abcd';
let test_object = {
  "0/0": 0,
  foo: bar,
  bar,
  test_method() {
    return 'test';
  }
};

console.info(test_object.foo === test_object.bar); // true
console.info(test_object["0/0"] === 0); // true

 

객체의 속성은 이름과 점 표기법으로 접근할 수 있습니다. 또한 대괄호로도 접근할 수 있습니다. 이 방법은 속성의 이름이 예시로 든 것처럼

"0/0" 과 같은 올바른 식별자가 아닌 경우에도 사용할 수 있습니다.

객체에서 찾을 수 없는 속성 값을 요청하면 객체는 undefined 를 반환합니다.

 

- 객체에는 undefined 를 저장하지 않는 것이 좋습니다.

 

물론 자바스크립트에선 이를 허용하지만, 그렇다고 그 속성이 해당 객체에 '없는' 것은 아닙니다. 속성을 제거하려면 delete 연산자를 사용해야 합니다.

 

- 객체에 중첩 깊이 제한은 없지만, 너무 깊게 만드는 것은 좋지 않습니다.

 

- typeof 연산자는 객체에 대해 'object' 문자열을 반환합니다.

 

- 속성을 찾을 때 쓰는 키 값은 대소문자를 구별합니다.

 

- Object.assign 함수로 객체의 속성들을 다른 객체로 복사할 수 있습니다.

 

let test = {key: 1};
let test_copy = Object.assign({}, test);

console.info(test_copy.key); // 1

 

Object.assign 함수의 두번째 인자로 오는 객체 속성을 첫번째 인자로 오는 객체에 복사하며, 원본 객체에는 영향을 주지 않습니다.

 

- 자바스크립트에서 객체는 다른 객체를 상속받을 수 있습니다.

 

자바스크립트의 상속은 여타 언어의 상속과는 전혀 다른 방식입니다. 자바스크립트의 상속은 데이터만 연결되므로 어플리케이션 구조를 취약하게 만들 가능성을 줄여 줍니다.

 

- Object.create 는 이미 있는 객체를 전달받아 이를 상속받는 새로운 객체를 반환합니다.

 

기존의 객체가 새로운 객체의 prototype 이 되는 것이며, 모든 객체가 프로토타입이 될 수 있습니다. 프로토타입을 상속받은 객체 역시 다른 새로운 객체의 프로토타입이 될 수 있습니다. 프로토타입 체인의 길이에 제한은 없지만, 짧은 것이 당연히 좋습니다.

객체에 없는 속성을 참조하려 할 때, undefined 를 반환하기 전에 시스템은 해당 객체의 프로토타입을 확인하고, 프로토타입의 프로토타입을 확인하는 식으로 거슬러 올라갑니다. 프로토타입 체인 중에 같은 이름의 속성을 발견하면, 마치 해당 객체가 가지고 있던 속성인 것처럼 값을 반환합니다.

 

- 객체의 속성에 값을 대입하면, 가장 새로운 객체 (프로토타입 체인의 가장 위쪽에 있는 객체) 만 변경됩니다. 프로토타입 체인의 다른 객체는 변경되지 않습니다.

 

let a = {key: 1};
let b = Object.create(a);

console.info(b.key); // 1
b.key += 1;
console.info(b.key); // 2
console.info(a.key); // 1
delete b.key;
console.info(b.key); // 1

 

- 프로토타입을 쓰는 주된 용도 중 하나는 함수를 저장하는 공간으로 사용하는 것입니다.

 

객체가 객체 리터럴로 만들어지면, 그 객체는 Object.prototype 을 상속받습니다. 비슷하게 배열은 Array.prototype, 숫자는 Number.prototype, 함수는 Function.prototype 을 상속받습니다. 배열이나 문자열의 상속받는 메서드는 꽤 유용하지만 Object.prototype 의 메서드들은 크게 쓸모가 없습니다.

 

- 상속이 있으므로 속성에도 두 가지 형태가 있습니다.

 

고유 속성 (가장 최근의 객체에만 있는 속성) 과 상속받은 속성 (프로토타입 체인에 존재하는 속성) 입니다. 대부분의 경우 두 가지 형태의 속성은 똑같이 동작합니다.

 

- 대부분의 객체는 hasOwnProperty 함수를 상속받지만, 신뢰도가 낮은 함수입니다.

 

이 함수는 문자열을 인자로 받아 객체가 해당 이름의 속성을 갖고 있으며 상속받지 않았다면 true 를 반환합니다. 하지만 객체가 hasOwnProperty 라는 이름의 속성을 갖고 있으면 Object.prototype.hasOwnProperty 메서드 대신 객체의 속성이 함수로서 호출됩니다.

 

- Object.assign 에 비교했을 때 Object.create 의 장점은 메모리를 덜 쓰지만, 눈에 띌 만큼 메모리가 절약되지는 않습니다.

 

- Object.create(null) 을 써서 객체가 아무것도 상속받지 않게 만들 수 있습니다.

 

이로 인해 원하지 않은 상속이나, 상속받은 값 때문에 헷갈리는 경우를 없게 만들 수 있습니다. 객체에는 명시적으로 집어넣은 속성 외에는 아무것도 없게 됩니다.

 

- Object.keys 함수는 상속받은 속성을 제외한 객체의 나머지 모든 속성의 이름을 문자열의 배열로 반환합니다.

 

let test = {a: 1, b: 2, c: 3};

console.info(Object.keys(test)); // [a, b, c]

 

배열의 문자열은 삽입된 순서로 나열됩니다.

 

- Object.freeze 함수는 객체를 전달받아서 동결 (변경 불가) 합니다.

 

해당 메서드는 깊은 동결이 아니기에 최상위 객체만 동결되고 프로토타입 체인의 다른 객체는 동결되지 않습니다 (얕은 동결). 깊은 동결을 하려면 nested object 의 속성을 재귀로 돌면서 전부 Object.freeze 하거나 외부 라이브러리 (lodash 와 같은) 를 사용해야 합니다.

 

- 동결된 불변 객체

 

객체가 절대 변하지 않는다는 점은 언어에 아주 강력한 최적화가 구현될 수도 있습니다. 불변 객체는 보안 면에서도 훌륭합니다.

 

- Object.freeze 와 const 는 아주 다른 일을 합니다.

 

const a = {key: 1};

a.key = 3;
console.info(a.key); // 3

a = {key: 4}; // TypeError: Assignment to constant variable

let b = Object.freeze({key: 1});

b.key = 3;
console.info(b.key); // 1

b = {key: 4};
console.info(b.key); // 4

 

Object.freeze 는 값에 적용되고, const 는 변수에 적용됩니다. 따라서 const 변수에 변경 가능한 객체를 저장해도 그 객체는 여전히 수정 가능합니다. 그 대신 const 변수에 다른 객체를 저장할 수는 없습니다. 반대로 일반 변수에 불변 객체를 지정해도 객체를 변경할 수 없지만, 변수에 다른 값을 저장할 수는 있습니다.

 

- WeakMap

 

자바스크립트에서 객체의 속성 이름에 문자열이 아닌 배열이나, 객체를 키로 사용하기 위해선 WeakMap 을 사용할 수 있습니다.

WeakMap 은 문자열을 제외한 다른 객체를 키로 씁니다.

 

Object WeakMap
object = Object.create(null) weakmap = new WeakMap()
object[key] weakmap.get(key)
object[key] = value weakmap.set(key, value)
delete object[key] weakmap.delete(key)

 

객체에 비밀스럽게 보관되어야 할 속성을 추가하려하고, 이 속성에 접근하려면 객체와 비밀 키에 접근할 수 있어야 하는 부분을 WeakMap 을 통해 구현할 수 있습니다.

 

const secret_key = new WeakMap();
secret_key.set(object, secret);

secret = secret_key.get(object);

 

객체와 비밀 키에 모두 접근할 수 있어야 비밀 속성을 볼 수 있습니다. 이 방법의 또 좋은 점은 동결된 객체에도 효율적으로 비밀 속성을 추가할 수 있다는 것입니다.

 

- WeakMap 은 그 내용에 대한 검사를 허용하지 않습니다.

 

키를 갖고 있지 않는 한, 값을 볼 수 없습니다. 또한 GC (가비지 컬렉터) 와 잘 맞습니다. 존재하는 키의 사본이 더 이상 없다면, 해당 키의 속성은 자동으로 삭제됩니다.

자바스크립트엔 비슷하게 Map 이라는 자료구조도 있지만, Map 에는 WeakMap 과 같은 보안이나 누출 방지 기능이 없습니다.

 

출처 : 자바스크립트는 왜 그 모양일까?

 

 

'Backend > Javascript' 카테고리의 다른 글

[Javascript] - Bottom value  (0) 2020.11.14
[Javascript] - String  (0) 2020.11.07
[Javascript] - Array  (0) 2020.10.24
[Javascript] - Boolean  (0) 2020.10.17
[Javascript] - Big Integer  (0) 2020.10.10