『JavaScirptデザインモード』(5)-チェーンコール

3892 ワード

JQueryを使ったことがある学生たちはきっと$という関数を知っていて、JQの中の方法のチェーン呼び出しの強さも知っています.実はチェーン呼び出しは文法の技にすぎません.初期操作を再利用することで、複雑な操作を少量のコードで表現する目的を達成することができます.このテクノロジーには、コードHTML要素オブジェクトを作成するファクトリと、このHTML要素に対していくつかの操作を実行する方法の2つの部分が含まれています.各この方法は、メソッド名に円点を付けた後に呼び出し接続に追加することができる.方法のチェーン呼び出しは、1つまたは複数のDOM要素を選択して1つまたは複数の操作を行うプロセスと見なすことができる.次に,下$の実装を簡単にシミュレーションし,チェーン呼び出しの原理を詳細に解析する.
$関数は通常、HTML要素またはHTML要素の集合を返します.ここでは、基本的なCSSセレクタ(#id,.class tag)をサポートし、入力されたDOMラベル要素をパッケージして返すとともに、入力されたパラメータの個数に基づいてパラメータに合致する要素を選択することができます.ただし、「p a」のようなCSSネスト選択はサポートされていません.
/*
 * @param {Object} name
 *        
 * @param {Object} type
 *        ,     
 *            
 */
var getElementsByClassName = function(name, type){
	var ret = [], 
		elems = document.getElementsByTagName(type || '*'),
		reg = new RegExp("(^|\\s)" + name + "($|\\s)");
	
	for(var i = 0, len = elems.length; i < len; ++i){
		if(reg.test(elems[i].className)) {
			ret.push(elems[i]);
		}
	}
	
	return ret;
};

/*
*         
* */
var $ = function(){
  var elems = [];
  for (var i = 0, len = arguments.length; i < len; ++i) {
    if ('string' === typeof arguments[i]) { //     
      if ('#' === arguments[i].charAt(0)) { //  ID
        var elem = doucment.getElementById(arguments[i].substr(1));
        if (elem) {
          elems.push(elem);
        }
      } else if ('.' === arguments[i].charAt(0)) {//  class
          elems = elems.concat(getElementsByClassName(arguments[i].substr(1)));
      } else { //    
          var tagElems = document.getElementsByTagName(arguments[i]);
          for (var j = 0, tagLen = tagElems.length; j < tagLen; ++j) {
            elems.push(tagElems[j]);
          }
      }
    } else if (1 === arguments.nodeType) { //      
        elems.push(arguments[i]);
    }
  }
  return elems;
};

この関数をコンストラクタに改造し、それらの要素セットをインスタンス属性に保存し、コンストラクタ関数に定義されたprototype属性が指すオブジェクト内のメソッドを呼び出し方法のインスタンスの参照(this)に戻すと、チェーン呼び出しを行う能力があります.まず、$関数をチェーン呼び出しをサポートするオブジェクトを作成するように改造するとともに、閉パッケージを使用してコンストラクタをプライベート関数として定義する必要があります.修正されたコードは次のとおりです.
//     ,    $  ,        
(function(){
	/*     ,        */
	function _$(els){
		this.elems = [];
		for (var i = 0, len = els.length; i < len; ++i) {
		if ('string' === typeof els[i]) { //     
			if ('#' === els[i].charAt(0)) { //  ID
				var elem = doucment.getElementById(els[i].substr(1));
				if (elem) {
					this.elems.push(elem);
				}
			} else if ('.' === els[i].charAt(0)) {//  class
					this.elems = this.elems.concat(getElementsByClassName(els[i].substr(1)));
			} else { //    
					var tagElems = document.getElementsByTagName(els[i]);
					for(var j = 0, tagLen = tagElems.length; j < tagLen; ++j){
						this.elems.push(tagElems[j]);
					}
				}
		} else if(1 === els.nodeType){ //      
			elems.push(els[i]);
		}
		}
	}
	
	//    $
	window.$ = function(){
		return new _$(arguments);
	};
})();

すべてのオブジェクトがそのプロトタイプオブジェクトのプロパティとメソッドを継承するため、プロトタイプオブジェクトに定義されたいくつかのメソッドをインスタンスオブジェクトの参照に戻すことができ、メソッドのチェーン呼び出しを実現します.私たちは先に_$をあげます.いくつかのプロトタイプメソッドを追加します.
_$.prototype = {
		each:function(fn, scope){
			for(var i = 0, len = this.elems.length; i < len; ++i){
				fn.call(scope||this, this.elems[i]);
			}
			return this;
		},
		setStyle:function(prop, value){
			this.each(function(elem){
				elem.style[prop] = value;
			});
			
			return this;
		},
		show:function(){
			this.each(function(elem){
				elem.style.display = 'block';
			});
			
			return this;
		}	
	};

これにより、チェーン呼び出しのパッケージ要素が構築され、$('div')を呼び出すことができる.setStyle('width', '100px').setStyle('height', '100px').setStyle('backgroudColor', 'red'); ここでは、ページのすべてのdiv要素を高さ100 px、幅100 px、背景色が赤に設定します.完全に自分のニーズやアイデアに合わせてプロトタイプ方法を増やすことができ、自分のJSライブラリを実現することができます.