(JS) 객체, 프로토타입, 기본 타입에 기능 추가
JS에서 단순 데이터 타입인 숫자, 문자열 등을 제외하면 배열, 함수, 정규표현식 등이 모두 객체로 이루어져 있다. 숫자, 문자열 등은 메소드가 있기 때문에 유사 객체라고 할 수 있지만 이들은 immutable 이다.
JS에서 객체는 변형 가능한 속성들의 집합이라고 할 수 있으며 이름과 값이 있는 속성들을 포함하는 컨테이너다.
JS에는 객체 하나에 있는 속성들을 다른 객체에 상속하게 해주는 프로토타입(prototype) 연결 특성이 있다. 프로토타입을 잘 활용하면, 객체를 초기화 하는 시간과 메모리 사용을 줄일 수 있다.
JS에서는 클래스가 따로 없고, new
와 Constructor
를 사용할 수는 있지만, 프로토타입과 클로저를 활용한 함수형 패턴 으로 객체를 정의한다.
2017/05/31 - [Web/Front-end] - [JS] 함수 #2. Call pattern, 생성자 대안(함수형 패턴), 상속
객체 리터럴
객체 리터럴은 {name:value}
형식으로 객체를 지정하는 것을 말한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
}
get value() { // getter
return this.value;
}
};
참조와 복사
객체는 참조 방식으로 전달된다. 절대 복사되지 않는다. 단, 문자열과 함수형 변수 (typeof === 'function'
)는 복사된다.
프로토타입(prototype)
모든 객체는 속성을 상속하는 프로토타입 객체에 연결돼 있다. 객체가 객체 리터럴로 생성되는 경우 JS 표준 객체인 Object
의 Object.prototype
객체에 연결된다. ( 속성 prototype
도 객체다. / Object.prototype
은 최상위 prototype
이다.)
그러나 실제로 출력해보면, 함수형 변수는 prototype
이 있는 반면 객체 리터럴은 없는 것으로 나오므로 주의.
1
2
3
4
var func\_obj = function () { };
alert(func\_obj.prototype); // [object Object]
var obj\_literal = { };
alert(obj\_literal.prototype); // undefined
Object.create()
객체를 생성할 때는 해당 객체의 프로토타입이 될 객체를 선택할 수 있다. Object.create()
메소드에 객체를 넘기면 해당 객체를 프로토타입으로 하는 새로운 객체를 생성해 반환해준다.
1
2
3
4
var foo = {
aa: "asd"
};
var foo\_v2 = Object.create(foo);
foo_v2.aa
는 기본값으로 "asd"
를 가지고 있으며, 이를 수정, 삭제하더라도, foo.aa
는 수정되지 않는다.
즉, 프로토타입은 수정이나 삭제와 무관하고 객체의 속성을 읽을 때만 사용한다.
객체에 있는 특정 속성에 접근하려고 할 때, 해당 속성이 객체에 없는 경우 프로토타입에서 찾아본다. 이러한 시도는 prototype chain을 따라 가장 마지막에 있는 Object.prototype
까지 계속해서 이어진다.
속성에 접근할 때 프로토타입 체인 탐색이 일어나므로 프로토타입 객체에 새로운 속성이 추가되면 해당 객체를 프로토타입으로 하는 객체들에 이 속성이 바로 추가된다.
리플렉션 ( reflection )
객체의 특정 속성이 객체의 속성인지, 프로토타입의 속성인지 확인하고 싶은 경우
1
if (typeof foo\_v2.aa !== 'function')
hasOwnProperty
는 프로토타입 체인을 탐색하지 않으며 true/false
를 반환한다.
1
if (foo\_v2.hasOwnProperty('aa'))
typeof
는 프로토타입 체인을 탐색하며 type
을 반환하기 때문에 특정 type
(e.g. !== function)을 가려내는데 유용하다.
delete
객체의 속성을 삭제할 수 있다. delete foo_v2.aa
이 역시 프로토타입 객체에 영향을 주지는 않기 때문에 aa
에 접근하면 프로토타입의 aa
가 나타난다. 즉, 프로토타입의 속성은 삭제되지 않는다.
기본 타입에 기능 추가
Object.prototype
에 메소드를 추가하면 모든 객체에서 그 메소드를 사용할 수 있다. 함수, 배열, 문자열, 숫자, 정규 표현식, 불리언 모두 이런식으로 기능을 추가할 수 있다.
Function.prototype
에 메소드를 추가하는 기능의 method
라는 메소드를 추가하면, 이를 이용해 간단히 메소드를 추가할 수 있다.
1
2
3
4
5
6
7
8
9
Function.prototype.method = function (name, func){
if(!this.prototype[name]){
this.prototype[name] = func;
}
return this;
};
JS에는 따로 구분된 정수형이 없어서 때때로 숫자형에서 정수 부분만 추출해야 하는 경우가 있다. 이를 Number.method
에 integer
라는 메소드를 추가해서 해결할 수 있다. 메소드 호출 패턴이기 때문에, this
는 해당 메소드를 호출한 객체가 된다.
1
2
3
4
5
6
7
Number.method('integer', function ( ) {
return Math[this < 0 ? 'ceiling' : 'floor'](this);
});
alert(13.2.integer());
문자열의 양 끝에 있는 빈칸을 지우는 메소드는 이런 식으로 추가한다.
1
2
3
4
String.method('trim', function ( ) {
return this.replace(/^\s+|\s+$/g, '');
});