jQuery设计模式(二)

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;
    }
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Media(中介者)模式</title> <script type="text/javascript" src="js/jquery.js"></script> </head> <body> <h2>Media(中介者)模式</h2> <p>行为设计模式。公开一个统一的接口,系统的不同部分可以通过该接口进行通信。</p> <p>确保组件的交互是通过这个中心点来处理,而不是通过显示地引用彼此。</p> <p>这种模式可以帮助我们解耦系统并提高组件的可重用性</p> <hr> <script> // 1 基本实现 var mediator = (function (){ // 存储可被广播或监听的topic var topics = {}; // 订阅一个topic,提供一个回调函数,一旦topic被广播就执行该回调 var subscribe = function (topic, fn){ if(!topics[topic]){ topics[topic] = []; } topics[topic].push({context: this, callback: fn}); return this; }; // 发布/广播事件到程序的剩余部分 var publish = function (topic){ var args; if(!topics[topic]){ return false; } // call 和 apply 方法都是用来调用“不属于自身的方法”,apply第参数必须是数组 // 下面的代码相当于 arguments.slice,但是arguments本身没有 slice方法 // slice 方法是用来截取数组 // arguments 是实参“数组” args = Array.prototype.slice.call(arguments, 1); for(var i = 0, l = topics[topic].length; i < l; i++){ var subscription = topics[topic][i]; subscription.callback.apply(subscription.context, args); // subscription.callback(arguments[1]); } return this; }; return { publish: publish, subscribe: subscribe, installTo: function (obj){ obj.subscribe = subscribe; obj.publish = publish; } } })(); </script> <h3>简单实现</h3> <form id="chatForm"> <label for="fromBox">Your Name:</label> <input id="fromBox" type="text"> <br> <label for="toBox">Send to:</label> <input id="toBox" type="text"> <br> <label for="chatBox">Message:</label> <input id="chatBox" type="text"> <button action="submit">Chat</button> </form> <div id="chatResult"></div> <script type="text/javascript"> $("#chatForm").on("submit", function (e){ e.preventDefault(); // 从UI上获取chat的数据 var text = $("#chatBox").val(), from = $("#fromBox").val(), to = $("#toBox").val(); // 将数据发布到newMessage主题上 mediator.publish("newMessage", {message: text, from: from, to: to}); }); // 将新信息附加到聊天记录结果上 function displayChat(data){ var date = new Date(), msg = data.from + " said \""+data.message+"\" to "+ data.to; $("#chatResult").prepend(""+msg+" ("+date.toLocaleTimeString()+")"); } // 记录消息日志 function logChat(data){ if(window.console){ console.log(data); } } // 通过mediator订阅提交的newMessage主题 mediator.subscribe("newMessage", displayChat); mediator.subscribe("newMessage", logChat); </script> </body> </html>

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值