티스토리 뷰

Java Script & HTML

ES5 주요 함수 분석

LichKing 2017. 5. 17. 22:17

얼마전 ES5 Array 메서드에 관한 포스팅을 올렸다.(http://multifrontgarden.tistory.com/176)

유용한 API들이 많이 추가됐는데 Array만 공부하는것보다 한번 훑어보는게 좋을것같아 추가 포스팅을 하게되었다. 사실 난 태생이 자바개발자라... ES5를 완벽하게 파해친다기보다는 알고있으면 유용하게 쓸것 같다고 매우 주관적으로 판단되는 추가사항만 들고왔다.


1. Object

1-1. Object.create

자바스크립트에서 상속을 이용하기위해서는 생성자 함수를 만든 뒤 프로토타입 체이닝을 이용해야한다.


var Human = function(name, age){
this.name = name;
this.age = age;
};

Human.prototype.introduce = function(){
return this.age + "살 " + this.name + "입니다.";
};

var Runner = function(){
this.run = function(){
return "달리고 있습니다."
}
};

Runner.prototype = new Human("LichKing", 29);

var runner = new Runner();

console.log(runner.run());
console.log(runner.introduce());


Runner 생성자 함수는 Human을 상속받고 있기때문에 Runner 인스턴스는 Human의 메서드들도 이용이 가능하다. 이런 문법은 기존 자바개발자들에겐 프로토타입 정도만 공부하면 쉽게 이해하고 사용할 수 있는 문법인데 사실상 자바스크립트 입장에서는 억지로 자바의 문법을 껴넣었다는 의견이 많았다. 동적으로 객체의 생성이 가능하고 필드 수정도 가능한 자바스크립트 입장에서는 생성자 함수라는것 자체가 어울리지 않고 객체레벨에서 상속이 가능해야한다는 것이다.


var human = {
name : "LichKing",
age : 29,
introduce : function(){
return this.age + "살 " + this.name + "입니다";
}
};

// 얘가 human을 상속하게 하고싶다!
var runner = {

}


실제 이런 상황에서는 객체끼리 상속관계를 맺어줄수가 없다. runner의 __proto__에 접근하여 할수있는 방법은 있지만 __proto__는 그 자체가 비표준이다.


var runner = {
run : function(){
return "달리고 있습니다";
}
};

runner.__proto__ = human;

// 되긴 된다
console.log(runner.introduce());
console.log(runner.run());


언제 스펙이 변할지모르는 비표준보다는 역시 표준 문법을 사용하는게 좋다. ES5에선 표준으로 이 문법을 지원하고있다.


var runner = Object.create(human, {
run : {
value : function(){
return "달리고 있습니다";
}
}
});

console.log(runner.introduce());
console.log(runner.run());


create() 함수의 첫번째 인자는 프로토타입 체이닝에 체인을 걸 객체가 오게된다. 그리고 두번째로 상속받는 객체의 필드를 정의하는 객체를 인자로 보내는데 인자형태가 익숙하지않다. 이 인자형태는 아래에서 좀 더 자세히 알아볼것이다. 저게 어렵고 익숙치않으면 이렇게 해도 상관없다.


var runner = Object.create(human);
runner.run = function(){
return "달리고 있습니다";
};

console.log(runner.introduce());
console.log(runner.run());


1-2. Object.defineProperty

함수명에서부터 알 수 있겠지만 객체의 필드를 정의하는 함수이다.


var obj = {};

Object.defineProperty(obj, "key", {
enumerable : true,
configurable : true,
writable : true,
value : "hello"
});

console.log(obj.key);

obj.key = "world";

console.log(obj.key);


obj 객체에 key라는 필드를 추가하는건데...음...사실 이건 이번 포스팅에 굳이 넣고싶지않았다. 문법을 보고 느낀점은 너무나도 자유분방한 자바스크립트에 최대한 안정성을 보장하고자 노력한거같긴한데 이걸 쓸까? 라는 생각이 들었기때문이다.

전문적인 프론트엔드 개발자라면 쓸일이 있을지 모르겠지만 아직 나는 프로덕션 코드에서 본적도, 내가 써본적도 없기때문이다. 필드하나 추가하기위해 누가 저런 장황한 문법을 반기겠는가? 하지만 위에서 소개한 Object.create() 함수의 두번째 인자때문에 작성을 하게됐다. 


이 함수를 좀 더 자세히 설명하면 첫번째 인자는 필드를 추가할 객체, 두번째 인자는 추가할 필드의 이름, 세번째 인자는 필드의 속성이다. 첫번째 두번째는 어려울게 없을테니 세번째를 좀 더 자세히 살펴보자.


enumerable : for-in 으로 객체의 속성을 탐색할때 포함시킬지 말지를 정한다.

configurable : 삭제 가능한 필드일지를 정한다.

writable : 필드의 값을 수정가능한지를 정한다.

value : 필드의 초기값을 정한다. 



writable, value 대신 get, set 함수를 설정할 수도 있다.


var obj = {};

var num = 100;
Object.defineProperty(obj, "key", {
enumerable : true,
configurable : true,
get : function(){
return 50;
},
set : function(value){
num = value;
}
});

obj.key = 200;

console.log(num);


아마도 객체의 필드를 외부 변수와 참조를 맺어주는 용도로 사용하는것 같다.

여러 속성을 정의할 수 있는 defineProperties 함수도 추가됐는데 해당 함수는 건너뛴다.


1-3. Object.getPrototypeOf

인자로 넘어오는 객체의 프로토타입을 추출한다. 위에서도 한번 말했지만 ES5에 추가된 내역들을 보면서 느낀점은 생성자 함수라는 (자바스크립트에서는) 이상한 문법이 아니라 자바스크립트답게 객체를 주로 활용하겠다는 의지가 보인다는 것이다. 기존에는 객체의 타입을 확인하기위해 instanceof 연산자를 사용했지만 이 역시 자바스크립트 입장에서는 함수에 종속적일 수 밖에 없다.


function Cons(){}

var obj = new Cons;

console.log(obj instanceof Cons);


instanceof의 우항은 함수만이 올 수 있으므로 객체간의 상속관계에서는 사용할 수가 없다. 이럴때 getPrototypeOf를 사용할 수 있다.


var obj1 = {
name : "LichKing"
};

var obj2 = Object.create(obj1);

console.log(Object.getPrototypeOf(obj2) === obj1);


예제를 짜다보니 변태적인 궁금증이 발견해서 이런 예제를 짜봤는데, 바로 윗단계의 프로토타입을 가져오는것 같다.


var obj1 = {
name : "LichKing"
};

var obj2 = Object.create(obj1);
var obj3 = Object.create(obj2);

console.log(Object.getPrototypeOf(obj3) === obj1);
console.log(Object.getPrototypeOf(obj3) === obj2);


1-4. Object.keys

이건 생각보다 꽤 많이 사용할 수도 있지 않을까 생각한다. 인자로 넘어오는 객체의 키를 배열로 반환한다.


var obj = {
a: "a",
b: "b"
};

console.log(Object.keys(obj));


위에서 익혔던 defineProperty로 정의한 필드를 enumerable false로 정의한건 배열에 포함되지 않는다.


var obj = {
a: "a",
b: "b"
};

Object.defineProperty(obj, "key", {
enumerable : false
});

console.log(Object.keys(obj));


1-5. Object.freeze

이건 넘어가려다가 함수명때문에 추가하게됐다. 자바스크립트 책은 아니지만 이펙티브 자바라는 책을 보다보면 객체를 얼린다 라는 표현이 나오는데 여기서도 본게 반가웠기때문이다. 얼린다는 표현이 생소할 수 있는데 불변(immutable)으로 만든다고 생각하면 된다. 즉 필드를 변경할 수 없다.


var obj = {
a: "a",
b: "b"
};

Object.freeze(obj);

console.log(obj.a);

obj.a = "";

console.log(obj.a);


1-6. Object.getOwnPropertyNames

프로토타입 체이닝에 걸려있는 필드를 제외하고 객체가 직접 들고있는 필드의 key를 배열형태로 반환한다. 내용이 간단하니 설명도 금방 끝나지만 사실 위에 길게 쓴 저런 함수들보다는 이런것들을 훨씬 많이 쓸것같다.


var obj = Object.create({a:"a"});
obj.b = "b";

// b만 반환된다
console.log(Object.getOwnPropertyNames(obj));


2. 기타

2-1. Function.prototype.bind

모든 함수들은 Function의 인스턴스이다. 이말인 즉 함수를 이런식으로 생성할 일은 없지만 new로 생성할 수 있다는 것이다.


var func = new Function("return 1+1");
console.log(func());


설명하고자하는건 이건 아니고 결국 모든 함수들은 Function.prototype을 체이닝에 걸게된다는 뜻이다. 즉 이번에 살펴볼 bind는 함수라면 모두 사용할 수 있다. bind는 함수의 컨텍스트를 변경하여 함수를 반환한다. call이랑 apply와 비슷하다고 느낄수도있지만 해당 함수들은 변경하여 실행시키는것이고, bind는 변경하여 반환한다는 차이가 있다(apply, call 역시 Function.prototype에 정의되어 있다.).


var obj = {
name : "LichKing",
speack : function(){
return "내이름은 " + this.name;
}
};

console.log(obj.speack());

var func = obj.speack.bind({name : "Lee"});

console.log(func());


2-2. String.prototype.trim

난 여태 trim이 없는줄 몰랐다. 유명한 명칭이니 예제만 보고 넘어가겠다.


var str = "     abcde";

console.log(str.trim());


2-3. Date.now

현재 시각을 double 타입으로 반환한다.


console.log(Date.now());


'Java Script & HTML' 카테고리의 다른 글

karma mocha 테스트 환경 구축  (0) 2017.09.16
JavaScript에서 정규 표현식 활용하기  (0) 2017.05.27
ES5 주요 함수 분석  (0) 2017.05.17
ES5 Array method  (0) 2017.05.13
유사배열객체  (0) 2017.05.06
Strict Mode  (0) 2017.04.30
댓글
댓글쓰기 폼