JavaScript設計モードItem 5--チェーンコール


1、チェーンコールとは
これは簡単に理解できます.例えば、
$(this).setStyle('color', 'red').show();

一般的な関数呼び出しとチェーン呼び出しの違い:メソッドの呼び出しが完了すると、return thisは現在の呼び出しメソッドのオブジェクトを返します.
function Dog(){
        this.run= function(){
            alert("The dog is running....");
            return this;//       Dog
        };
        this.eat= function(){
            alert("After running the dog is eatting....");
            return this;//       Dog

        };
        this.sleep= function(){
            alert("After eatting the dog is running....");
            return this;//       Dog

        };
    }
    //       ;
/* var dog1 =new Dog(); dog1.run(); dog1.eat(); dog1.sleep();*/
    var dog2 = new Dog();
    dog2.run().eat().sleep();

2、分解チェーン呼び出し
チェーンコールは2つの部分です.
  • 1.操作オブジェクト(すなわち、上述の例の$(this))
  • 2.操作方法(前例のsetStyleやshowなど、具体的に何をするか)
  • 操作オブジェクトと操作方法の実装方法
    一般的な$関数を作成します.
    function $(){
        var elements = [];
        for(var i= 0,len=arguments.length; i<len; i++){
            var element = arguments[i];
            if(typeof element==='string'){
                element = document.getElementById(element);
            }
            if(arguments.length==1){
                return element;
            }
            elements.push(element);
        }
        return elements;
    }

    しかし、この関数をコンストラクタに改造し、それらの要素を配列としてインスタンス属性に保存し、コンストラクタ関数のprototype属性が指すオブジェクトに定義されたすべてのメソッドをメソッドを呼び出すためのインスタンスの参照に戻すと、チェーン呼び出しの能力があります.(これだけ言ったのは、各方法の最後のreturn this;です)
    まず、この$関数をファクトリメソッドに変更する必要があります.チェーン呼び出しをサポートするオブジェクトの作成を担当します.この関数は、元の共通インタフェースを使用できるように、要素配列形式のパラメータを受け入れることができるはずです.これにより、チェーン呼び出しを行う能力が得られます.
    改造後は以下の通り:
    (function(){
        function _$(els){
            this.elements = [];//                   ,
            for(var i= 0, len=els.length; i<len; i++){
                var element = els[i];
                if(typeof element==='string'){
                    element = document.getElementById(element);
                }
                this.elements.push(element);
            }
        }
    
        _$.prototype = {
            each: function(fn){
                for(var i= 0,len=this.elements.length; i<len; i++){
                    fn.call(this, this.elements[i]);
                }
                return this; //        return this;
            },
            setStyle: function(prop, val){
                this.each(function(el){
                    el.style[prop] = val;
                });
                return this; //        return this;
            },
            show: function(){
                var that = this;
                this.each(function(el){
                    that.setStyle('display', 'block');
                });
                return this; //        return this;
            },
            addEvent: function(type, fn){
                var add = function(el){
                    if(window.addEventListener){
                        el.addEventListener(type, fn, false);
                    }else if(window.attachEvent){
                        el.addEvent('on'+type, fn);
                    }
                };
                this.each(function(el){
                    add(el);
                });
                return this; //        return this;
            }
        }
        window.$ = function(){
            return new _$(arguments);
        }
    })();

    最後にreturn thisでは、呼び出しメソッドのオブジェクトを呼び出しチェーン上の次のメソッドに渡します.
    3、シミュレーションjquery下位チェーンプログラミング
    //      
    //  1                   
    //  2                 (    var     )
    
    (function(window , undefined){
        // $                         '_'       (  )
        function _$(arguments){
            //    ...     ID   
            //        id   
            var idselector = /#\w+/ ;
            this.dom ;      //             
            //           dom   arguments[0] = '#inp'
            if(idselector.test(arguments[0])){
                this.dom = document.getElementById(arguments[0].substring(1));
            } else {
                throw new Error(' arguments is error !');
            }
        };
    
        //  Function                 
        Function.prototype.method = function(methodName , fn){
            this.prototype[methodName] = fn ;
            return this ; //       
        }
    
        //  _$               
        _$.prototype = {
            constructor : _$ ,
            addEvent:function(type,fn){
                //              
                if(window.addEventListener){// FF 
                    this.dom.addEventListener(type , fn);
                } else if (window.attachEvent){// IE
                    this.dom.attachEvent('on'+type , fn);
                }
                return this ; 
            },
            setStyle:function(prop , val){
                this.dom.style[prop] = val ;
                return this ;
            }
        };
    
    
         // window                   
        window.$ = _$ ;
        //         
        _$.onReady = function(fn){ 
            // 1      _$         window 
            window.$ = function(){
                return new _$(arguments);
            };
            // 2          
            fn();
            // 3       
            _$.method('addEvent',function(){
                // nothing to do
            }).method('setStyle',function(){
                // nothing to do
            });
    
        };
    
    })(window); //       window      
    
    
    $.onReady(function(){
        var inp = $('#inp');
        //alert(inp.dom.nodeName);
        //alert($('#inp'));
        inp.addEvent('click',function(){
            alert('     !');
        }).setStyle('backgroundColor' , 'red');
    });
    

    4、コールバック関数を用いてチェーン呼び出しをサポートする方法からデータを取得する
    チェーン呼び出しは賦値器メソッドに適していますが、取値器メソッドでは不便です.各メソッドがthisを返すからです.
    しかし、融通のきく方法はあります.それはコールバック関数です.
    コールバック関数が使用されていない場合
    //without callback
    window.API = window.API || function(){
        var name = 'JChen';
        this.setName = function(newName){
            name = newName;
            return this;
        };
        this.getName = function(){
            return name;
        };
    };
    var o = new API();
    console.log(o.getName());
    console.log(o.setName('Haha').getName());

    コールバック関数を使用する場合
    //with callback
    window.API2 = window.API2 || function(){
        var name = 'JChen';
        this.setName = function(newName){
            name = newName;
            return this;
        };
        this.getName = function(callback){
            callback.call(this, name);
            return this;
        };
    };
    var o2 = new API2();
    o2.getName(console.log).setName('Hehe').getName(console.log);

    コールバック関数を使用するときcallback.call(this,name)は一般的には問題ありませんが、この例ではconsole.ロゴ、それでは問題があります.なぜならconsoleのthisはwinodwではなくconsoleを指しているからです.
    この問題もよく解決した.次のようになります.
    //with callback
    window.API2 = window.API2 || function(){
        var name = 'JChen';
        this.setName = function(newName){
            name = newName;
            return this;
        };
        this.getName = function(callback){
            callback.call(this, name);
            return this;
        };
    };
    var o2 = new API2();
    var log = function(para){
        console.log(para);
    };
    o2.getName(log).setName('Hehe').getName(log);

    5、まとめ
    チェーン呼び出しというスタイルは、コードの作成を簡素化し、コードをより簡潔で読みやすくするとともに、1つのオブジェクト変数を複数回繰り返し使用することを回避します.