##1. 타입 검출
typeof 는 때때로 불합리한 반환값을 반환합니다. 예를 들어 RegExp 객체는 object 를 반환합니다. 테스트 코드:
var regex = /^what$/i;
regex = new RegExp('^what$');
alert(typeof regex);
instanceof 는 페이지에 여러 frame 이 있을 때 사용할 수 없습니다. 서로 다른 frame 의 객체에 대해 instanceof 는 false 를 반환합니다
Object.prototype.toString.call(value) === '[object Array/Function...]' 를 사용하여 타입 검사를 수행할 수 있습니다. 또한 네이티브 객체와 사용자 정의 객체를 구분하는 데에도 사용할 수 있습니다. 예를 들어:
[object JSON]//네이티브 JSON 객체
[object Object]//사용자 정의 JSON 객체
주의:IE 에서 COM 객체 형태로 구현된 함수 객체는 toString 이 [object Function] 을 반환하지 않습니다
##2. 스코프 안전 생성자
new 연산자로 생성자를 호출하면 새로 생성된 객체에 속성이 추가되지만, 생성자를 직접 호출하면 전역 객체 window 에 속성이 추가됩니다
전역 스코프를 오염시키지 않기 위해 다음과 같은 생성자를 사용할 수 있습니다:
/* 전역 스코프를 오염시킬 수 있음
function Student(name){
this.name = name;
}
*/
//스코프 안전 생성자
function Student(name){
if(this instanceof Student){
this.name = name;
}
else{
return new Student(name);
}
}
위의 생성자는 생성자를 직접 호출하여 전역 객체에 의도치 않게 속성을 추가하는 것을 방지할 수 있지만, 이 방식으로 상속을 구현하면 문제가 발생할 수 있습니다. 타입 검사로 인해 상속이 실패할 수 있습니다
##3. 지연 로딩 (중복된 분기 검사 방지)
-
첫 번째 분기 검사 실행 시 기존 함수를 덮어씁니다. 예를 들어:
function detect(){ if(...){ detect = function(){ // } } else if(...){ detect = function(){ // } } else... } -
즉시 실행되는 익명 함수를 사용하여 익명 함수를 반환함으로써 지연 로딩을 구현할 수 있습니다. 예를 들어:
var detect = (function(){ if(...){ return function(){ // } } else if(...){ return function(){ // } } else... })();
첫 번째 방식은 첫 호출 시 성능 손실이 있지만 이후 호출에서는 성능 손실이 없습니다. 두 번째 방식은 첫 호출 시에도 성능 손실이 없습니다. 시간 소모적인 작업을 코드 첫 로딩 시에 배치했기 때문입니다
##4. 함수 바인딩 (실행 환경 지정)
다음 함수를 사용하여 함수의 실행 환경을 지정하고 새 함수를 생성할 수 있습니다:
function bind(fun, context){
return function(){
return fun.apply(context, arguments);
}
}
기존 함수를 기반으로 새 함수를 쉽게 생성할 수 있습니다. [IE9+] 에는 네이티브 bind 메서드가 있습니다. 예를 들어 var newFun = fun.bind(obj);
주의: 함수 바인딩에는 메모리 소비가 많고 실행이 느리다는 단점이 있습니다
##5. 함수 커링 (함수 중첩이라고도 하며, 일부 매개변수 지정 가능)
커링 함수를 생성하는 일반적인 방법:
function curry(fun){
var args = Array.prototype.slice.call(arguments, 1);//첫 번째 매개변수 fun 제거, 지정된 매개변수 값 얻기
return function(){
var innerArgs = Array.prototype.slice.call(arguments);//내부 arguments 객체를 배열로 변환 (concat 메서드 사용 위해)
var finalArgs = args.concat(innerArgs);//매개변수 목록 결합
return fun.apply(null, finalArgs);//결합된 매개변수 목록을 fun 에 전달
}
}
또는 bind 메서드를 강화하여 커링 구현:
function bind(fun, context){
var args = Array.prototype.slice.call(arguments, 2);//첫 2 개 매개변수 제거
return function(){
var innerArgs = Array.prototype.slice.call(arguments);//curry 와 동일
var finalArgs = args.concat(innerArgs);//curry 와 동일
return fun.apply(context, finalArgs);//실행 환경과 매개변수 지정
}
}
주의: 커링과 bind 모두 추가 오버헤드가 존재합니다. 남용하지 마십시오
##6. 변조 방지 객체
-
확장 불가 객체 (새 속성 추가 불가)
var obj = {a : 1, b : 2}; alert(Object.isExtensible(obj));//true Object.preventExtensions(obj);//obj 를 확장 불가로 설정 alert(Object.isExtensible(obj));//false obj.c = 3; alert(obj.c);//undefined
주의: 확장 불가 설정 작업은 취소할 수 없습니다(되돌릴 수 없음). 설정 후 새 속성을 추가할 수 없지만 기존 속성 수정/삭제는 가능합니다
-
밀봉 객체 (기존 속성만 수정 가능, 삭제 또는 추가 불가)
var obj = {a : 1, b : 2}; Object.seal(obj);//밀봉 객체로 설정 alert(Object.isSealed(obj));//true obj.c = 3; alert(obj.c);//undefined delete obj.a;//엄격 모드에서 오류 alert(obj.a);//1 -
동결 객체 (읽기 전용, 접근자 속성은 쓰기 가능)
var obj = {a : 1, b : 2}; Object.freeze(obj);//밀봉 객체로 설정 alert(Object.isFrozen(obj));//true obj.a = 3; alert(obj.a);//1
위의 구현은 모두ES5 에서 추가된 부분입니다. 브라우저 지원성은 알 수 없으며, 로컬 테스트에서는*[IE8-] 는 지원하지 않습니다*. Chrome 과 FF 는 지원합니다
##7. 함수 스로틀링
시간이 소요되는 큰 작업을 작은 부분으로 나누고 setTimeout 으로 실행을 제어합니다
장점: 페이지 응답 속도가 향상됩니다
단점: 논리적 일관성이 없어지고 구현 난이도가 증가합니다. 또한 완전한 트랜잭션이 분리되므로 트랜잭션 제어 구현이 어렵습니다
##8. 옵저버 패턴
사용자 정의 이벤트를 사용하여 옵저버 패턴을 구현할 수 있습니다:
function EventTarget(){
this.handlers = {};
}
EventTarget.prototype = {
constructor: EventTarget,
addHandler: function(type, handler){
if (typeof this.handlers[type] == "undefined"){
this.handlers[type] = [];
}
this.handlers[type].push(handler);
},
fire: function(event){
if (!event.target){
event.target = this;
}
if (this.handlers[event.type] instanceof Array){
var handlers = this.handlers[event.type];
for (var i=0, len=handlers.length; i < len; i++){
handlers[i](event);
}
}
},
removeHandler: function(type, handler){
if (this.handlers[type] instanceof Array){
var handlers = this.handlers[type];
for (var i=0, len=handlers.length; i < len; i++){
if (handlers[i] === handler){
break;
}
}
handlers.splice(i, 1);
}
}
};
사용 방법은 다음과 같습니다:
function handleMessage(event){
alert("Message received: " + event.message);
}
//새 객체 생성
var target = new EventTarget();
//이벤트 핸들러 추가
target.addHandler("message", handleMessage);
//이벤트 트리거
target.fire({ type: "message", message: "Hello world!"});
//이벤트 핸들러 제거
target.removeHandler("message", handleMessage);
//다시 이벤트 트리거, 이벤트 핸들러가 없어야 함
target.fire({ type: "message", message: "Hello world!"});
아직 댓글이 없습니다