2 실수하기 쉬운 것들
2-1. 객체 확장하기
최악의 실수는 Object.prototype을 확장하는 것이다.
이 것은 모든 객체가 추가된 프로퍼티를 받는 다는 것을 의미하고, 어떤 객체의 프로퍼티를 순회할 때 새로 추가한 프로퍼티가 같이 순회되어 문제가 될 수 있다.
예제 코드(객체에 있는 모든 프로퍼티 이름(key)의 배열을 반환하는 메서드)
Object.prototype.keys = function(){
var keys = [];
for(var p in this) keys.push(p);
return keys;
};
var obj = { a : 1, b : 2, c : 3};
console.log(obj.keys().length == 3); // false
코드만 보면 테스트에 성공할 것 같지만, 실패한다.
그 이유는 Object에 keys() 메서드를 추가했기 때문이다. 모든 객체에 새로 추가한 프로퍼티가 존재하고 프로퍼티 개수인 count에도 포함된다. ['a', 'b', 'c', 'keys'] 로 존재
이 문제를 해결하기 위해 우리는 hasOwnProperty()메서드를 사용할 수 있다.
프로퍼티가 실제로 객체 인스턴스에 저장되었는지 아니면 프로토타입으로부터 온 것인지를 판단하는데 사용하는 메소드이다.
Object.prototype.keys = function(){
var keys = [];
for(var i in this) {
if(this.hasOwnProperty(i)) keys.push(p);
}
return keys;
};
var obj = { a : 1, b : 2, c : 3};
console.log(obj.keys().length == 3); // true
2-2. Number 객체 확장하기
Object를 제외한 대부분의 네이티브 객체 프로토타입을 확장하는 방식은 보통 안전하다.
하지만 본질적으로 Number가 문제가 될 수 있다.
자바스크립트 엔진이 숫자와 숫자 객체의 프로퍼티를 파싱하는 방법 때문에 혼란을 초래할 수 있다.
Number.prototype.add = function(num){
return this + num;
}
var n = 5;
console.log(n.add(3) == 8); // 변수를 사용하여 테스트 (true)
console.log((5).add(3) == 8); // 표현식 형태를 이용해 테스트 (true)
console.log(5.add(3) == 8); // 리터럴 형식으로 테스트 (에러)
문법 파서가 리터럴의 경우를 처리하지 못한다. 이렇게 되는 경우 일관성이 무너지기 때문에 용법을 명시하여 사용하여야 한다.
2-3. 네이티브 객체의 하위 클래스 만들기
네이티브 객체의 하위 클래스를 만들고 싶을 때는, 네이티브 객체 전체를 상속하기보다는 네이티브 객체의 기능과는 별개인 기능을 구현하는 것이 더 나은 전략이다.
function MyArray(){}
MyArray.prototype.length = 0;
(function(){
// 배열로 원하는 기능만 복사
var methods = ['push', 'pop', 'shift', 'unshift', 'slice', 'splice', 'join'];
for(var i=0; i<methods.length; i++) (function(name){
MyArray.prototype[name] = function(){
return Array.prototype[name].apply(this, arguments);
};
})(methods[i]);
})();
var mine = new MyArray();
mine.push(1,2,3);
console.log(mine.length == 3);
console.log(!(mine instanceof Array))
2-4. 인스턴스 생성 이슈
"일반" 함수와 생성자, 두 가지 목적으로 함수가 동작한다.
이런점 때문에 누군가가 잘못된 방식으로 함수를 사용한 경우, 발생할 수 있는 문제점들을 살펴보자
function User(first, last){
this.name = first + " " + last;
}
var user = User("corn", "sunghyun");
console.log(user); // undefiend
console.log(user.name); // error
new 연산자를 사용하지 않으면 일반 형태로 함수가 호출되게 된다.
따라서 위의 코드에는 this가 window 전역객체가 되므로 window.name에 corn sunghyun이 추가된다.
=> 유효범위가 오염됨.
함수가 생성자로 호출되면, 호출 컨텍스트는 새로 생성된 객체 이다. 하지만 일반 함수로 호출되었을 때는 전역 객체가 된다.
function User(first, last){
if(!(this instanceof arguments.callee)){
return new User(first, last);
}
this.name = first + " " + last;
}
var user = User("corn", "sunghyun");
console.log(user); // User { name : "corn sunghyun"}
console.log(user instanceof User); // true
console.log(user.name); // corn sunghyun
arguments.callee를 통해 현재 실행하고 있는 함수에 대한 참조를 얻을 수 있다. instanceof 연산자를 사용하여 함수가 올바르게 호출되었는지 판단할 수 잇다. new 연산자로 호출이 안되었을시 User 인스턴스를 만들어 준다.
'프로그래밍 노트 > JAVASCRIPT' 카테고리의 다른 글
[Javascript] 정규 표현식 살펴보기(정규식_2) (0) | 2019.01.21 |
---|---|
[Javascript] 정규식이 멋진 이유(정규식_1) (0) | 2019.01.21 |
[Javascript] 객체지향과 프로토타입_1 (0) | 2019.01.10 |
[Javascript] 1종객체(함수) 가지고 놀기_2 (가변인자목록 arguments) (0) | 2019.01.06 |
[Javascript] 1종객체(함수) 가지고 놀기_1 (0) | 2018.12.20 |