Iterator(迭代器)
模式Iterator是一种设计模式,其中,迭代器顺序访问聚合对象的元素,无需公开其基本形式。
迭代器封装特定迭代如何发生的内部结构。对于jQuery的jQuery.fn.each()迭代器,我们实际上能够使用jQuery.each()后面的底层代码来遍历一个集合,而不需要阅读或者理解提供这种功能的后台工作代码。
这种模式可以被视为一种特殊的facade,我们显式地处理与迭代相关的问题。
$.each(["a","b","c","d"],function(index , value){
console.log(index + ":" + value )
});
$("li").each(function (index) {
console.log(index + ":" + $(this).text());
})
这里我们看到jQuery.fn.each()的源码:
each: function( callback, args ) {
return jQuery.each( this, callback, args );
}
随后是jQuery.each()后面的代码,它处理了两种遍历对象:
each: function( obj, callback, args ) {
var value,
i = 0,
length = obj.length,
isArray = isArraylike( obj );
if ( args ) {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.apply( obj[ i ], args );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.apply( obj[ i ], args );
if ( value === false ) {
break;
}
}
}
// A special, fast, case for the most common use of each
} else {
if ( isArray ) {
for ( ; i < length; i++ ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
} else {
for ( i in obj ) {
value = callback.call( obj[ i ], i, obj[ i ] );
if ( value === false ) {
break;
}
}
}
}
return obj;
}
延迟初始化
延迟初始化是一种设计模式,它能延迟昂贵的过程,直到第一个实例需要时。其中一个示例就是jQuery中的ready()函数,当DOM准备就绪时,它仅执行一次回调。
实例ready方法
jQuery.fn.ready = function( fn ) {
// Add the callback
jQuery.ready.promise().done( fn );
return this;
};
实际实现
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
// Trigger any bound ready events
if ( jQuery.fn.triggerHandler ) {
jQuery( document ).triggerHandler( "ready" );
jQuery( document ).off( "ready" );
}
}
Proxy(代理)模式
我们有时候需要控制对象的访问权限和上下文,这就是Proxy模式有用的地方。
当一个昂贵的对象应被实例化的时,Proxy模式可以帮助我们对其进行控制,提供高级的方法来引用对象,或修改对象,让它在特定的上下文中以一种特殊方式发挥作用。
在jQuery核心中,存在jQuery.proxy()方法,它接受函数作为参数,并返回一个始终具有特定上下文的新对象。这确保函数中的this值是我们所需要的值。
在下面的示例中它就很有用,在click事件处理程序内使用计时器时延迟执行。
$("button").on("click", function () {
setTimeout(function () {
$(this).addClass("active"); //this指向window
},100)
})
为了解决这个问题,我们可以使用jQuery.proxy()来实现代理模式类型。通过使用我们希望赋给this的函数和值来调用它,它实际上会返回一个函数,它会在正确的上下文保留该值。
$("button").on("click", function () {
setTimeout($.proxy(function(){
console.log(this.value);
},this),100);
})
jQuery源码中的实现:
proxy: function( fn, context ) {
var tmp, args, proxy;
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
// Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !jQuery.isFunction( fn ) ) {
return undefined;
}
// Simulated bind
args = slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
};
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
}