엄범


JS에서 단순 데이터 타입인 숫자, 문자열 등을 제외하면 배열, 함수, 정규표현식 등이 모두 객체로 이루어져 있다.

숫자, 문자열 등은 메소드가 있기 때문에 유사 객체라고 할 수 있지만 이들은 immutable이다.

JS에서 객체는 변형 가능한 속성들의 집합이라고 할 수 있으며 이름과 값이 있는 속성들을 포함하는 컨테이너다.


JS에는 객체 하나에 있는 속성들을 다른 객체에 상속하게 해주는 프로토타입(prototype) 연결 특성이 있다. 프로토타입을 잘 활용하면, 객체를 초기화 하는 시간과 메모리 사용을 줄일 수 있다.


JS에서는 클래스가 따로 없고, ``js new``와 ``Constructor``를 사용할 수는 있지만, 프로토타입과 클로저를 활용한 함수형 패턴으로 객체를 정의한다.

2017/05/31 - [Web/Front-end] - [JS] 함수 #2. Call pattern, 생성자 대안(함수형 패턴), 상속


객체 리터럴

객체 리터럴은 ``js {name:value}``형식으로 객체를 지정하는 것을 말한다.

```js

const foo = {

    "": 5,

    a_s: "valid name",

    "a-s": "unvalid name",

    value : 0,

    reiter: {

        a: 33

    },

    add_value: function() {    // arrow function을 쓰면 value가 증가하지 않는다!

        this.value += 1;

    }

};

```


undefined 방지

``a_s``처럼 유효한 이름일 경우 ``js ""``로 감싸주지 않아도 되며, ``.``연산자로 접근할 수 있다. 객체 접근은 보통 ``.``연산자를 사용하는 것이 좋다.

존재하지 않는 속성(``undefined``)의 속성을 참조하려 하면 ``TypeError``가 발생한다.

이를 방지하기 위해 ``&&``를 사용하면 좋다.

```js

obj.und                      // undefined

obj.und.value                // throw "TypeError"

obj.und && obj.und.value     // undefined

```


참조와 복사

객체는 참조 방식으로 전달된다. 절대 복사되지 않는다.

단, 문자열과 함수형 변수(``js typeof === 'function'``)는 복사된다.


프로토타입(prototype)

모든 객체는 속성을 상속하는 프로토타입 객체에 연결돼 있다.

객체가 객체 리터럴로 생성되는 경우 JS 표준 객체인 ``js Object``의 ``js Object.prototype`` 객체에 연결된다. 

( 속성 ``prototype``도 객체다. / ``js Object.prototype``은 최상위 ``prototype``이다.)


그러나 실제로 출력해보면, 함수형 변수는 ``prototype``이 있는 반면 객체 리터럴은 없는 것으로 나오므로 주의.

```js

var func_obj = function () { };

alert(func_obj.prototype);     // [object Object]

var obj_literal = { };

alert(obj_literal.prototype);  // undefined

```


Object.create()

객체를 생성할 때는 해당 객체의 프로토타입이 될 객체를 선택할 수 있다.

``js Object.create()`` 메소드에 객체를 넘기면 해당 객체를 프로토타입으로 하는 새로운 객체를 생성해 반환해준다.

```js

var foo = {

    aa: "asd"

};

var foo_v2 = Object.create(foo);

```

``js foo_v2.aa``는 기본값으로 ``js "asd"``를 가지고 있으며, 이를 수정, 삭제하더라도, ``js foo.aa``는 수정되지 않는다.

즉, 프로토타입은 수정이나 삭제와 무관하고 객체의 속성을 읽을 때만 사용한다.

객체에 있는 특정 속성에 접근하려고 할 때, 해당 속성이 객체에 없는 경우 프로토타입에서 찾아본다. 이러한 시도는 prototype chain을 따라 가장 마지막에 있는 ``js Object.prototype``까지 계속해서 이어진다. 


속성에 접근할 때 프로토타입 체인 탐색이 일어나므로 프로토타입 객체에 새로운 속성이 추가되면 해당 객체를 프로토타입으로 하는 객체들에 이 속성이 바로 추가된다.


리플렉션 ( reflection )

객체의 특정 속성이 객체의 속성인지, 프로토타입의 속성인지 확인하고 싶은 경우

```js

if (typeof foo_v2.aa !== 'function')

```

``hasOwnProperty``는 프로토타입 체인을 탐색하지 않으며 ``js true/false``를 반환한다.

```js

if (foo_v2.hasOwnProperty('aa'))

```

``js typeof``는 프로토타입 체인을 탐색하며 ``type``을 반환하기 때문에 특정 ``type``(e.g. !== function)을 가려내는데 유용하다.


delete

객체의 속성을 삭제할 수 있다. 

``js delete foo_v2.aa``

이 역시 프로토타입 객체에 영향을 주지는 않기 때문에 ``aa``에 접근하면 프로토타입의 ``aa``가 나타난다. 

즉, 프로토타입의 속성은 삭제되지 않는다.


기본 타입에 기능 추가

``js Object.prototype``에 메소드를 추가하면 모든 객체에서 그 메소드를 사용할 수 있다.

함수, 배열, 문자열, 숫자, 정규 표현식, 불리언 모두 이런식으로 기능을 추가할 수 있다.


``js Function.prototype``에 메소드를 추가하는 기능의 ``method``라는 메소드를 추가하면, 이를 이용해 간단히 메소드를 추가할 수 있다.

```js

Function.prototype.method = function (name, func){

if(!this.prototype[name]){

this.prototype[name] = func;

}

    return this;

};

```


JS에는 따로 구분된 정수형이 없어서 때때로 숫자형에서 정수 부분만 추출해야 하는 경우가 있다.

이를 ``js Number.method``에 ``integer``라는 메소드를 추가해서 해결할 수 있다.

메소드 호출 패턴이기 때문에, ``this``는 해당 메소드를 호출한 객체가 된다.

```js

Number.method('integer', function ( ) {

return Math[this < 0 ? 'ceiling' : 'floor'](this);

});


alert(13.2.integer());

```


문자열의 양 끝에 있는 빈칸을 지우는 메소드는 이런 식으로 추가한다.

```js

String.method('trim', function ( ) {

return this.replace(/^\s+|\s+$/g, '');

});

```