林秀栋的技术博客

设计模式(二十二) 链模式

html

<div id="aa"></div>
<div id="bb"></div>

js

/*
//链模式
//var A = function(){};A.prototype = {sk:function(){...}};
//一般想调用对象里的方法,可以new A().sk()
//但A.sk()或A().sk()都不行
//前者sk绑定在A的原型而非A,后者是A的执行结果没有返回值所以找不到sk

//可以找人帮忙
var A = function(){
	return B;
}
var B = A.prototype = {
	kk: 2,
	sk: function(){
		return this.kk;
	}
}
A().sk();	//访问sk
//jquery中,为了减少变量创建,直接把B看做A的一个属性
var A = function(){
	return A.fn;
}
A.fn = A.prototype = {
	//...
};
但在jQ中是为了返回元素,这里返回的是A.fn对象。所以需要增加一个获取元素的init方法
var A = function(selector){
	return A.fn.init(selector);
}
A.fn = A.prototype = {
	init: function(selector){
		return document.getElementById(selector);
	},
	kk: 2,
	sk: function(){
		return this.kk;
	}
};
console.log(A('aa'));	//<div id="aa"></div>*/

/*
//但这样无法获取sk等其他方法
//而init中this指向的就是A.fn,返回this即可
//但这样就无法获取元素
//不过既然this指向的是对象,那么就可以设置属性,设置为数组,并增加length属性
var A = function(selector){
	return A.fn.init(selector);
	//return new A.fn.init(selector);
}
A.fn = A.prototype = {
	init: function(selector){
		this[0] = document.getElementById(selector);
		this.length = 1;	//为对象增加length属性
		return this;
	},
	kk: 2,
	sk: function(){
		return this.kk;
	}
};
console.log(A('aa'));	//Object{0:div#aa, init:function, kk: 2, length: 1, sk: function}
//console.log(A('bb'));	//若放开这条,会把上面的输出结果也覆盖为#bb
//因为每次返回的A.fn.init(selector)都指向同一对象
//只要把 return A.fn.init(selector); 改为 return new A.fn.init(selector); 即可
//但这时返回的对象没有sk等方法属性,无法使用
//因为A.fn.init(selector)的this返回的是当前对象,即A.fn和A.prototype
//而new后this指向的是A.fn.A.init
//因为new A.fn.init(selector)的构造函数是A.fn.init或A.init(从A.prototype找到)
//即A.fn.init=A.init,把A.init带入A.fn.init的init中可得A.fn.A.init
//而jQ中_proto_原型指向的不是A.fn.A.init,而是jQuery[0]
//因为jQ中加了A.fn.init.prototype = A.fn;*/

//为此A可以改为
var A = function(selector){
	return new A.fn.init(selector);
}
A.fn = A.prototype = {
	//强化构造器
	constructor: A,
	init: function(selector){
		this[0] = document.getElementById(selector);
		this.length = 1;	//为对象增加length属性
		return this;
	},
	kk: 2,
	sk: function(){
		return this.kk;
	},
	//这时输出的还是{}的对象类型,
	//而jQ输出的是类似数组的jQ对象类型
	//只需要增加下面3行代码,即可输出这种形式
	//增强数组
	//好像只要加splice也可以
	//一个 Javascript 对象,只要定义了 length 属性和 splice 方法,它看起来就像一个数组
	//即使splice: function(){}也可以
	push:[].push,
	sort:[].sort,
	splice:[].splice
};
A.fn.init.prototype = A.fn;
console.log(A('aa'));
//此时_proto_指向A,且可以正常使用其他方法
//另外像取类名等也可以循环this[i]=...

//扩展对象
A.extend = A.fn.extend = function(){
	//第一个参数为源对象,后面的是扩展对象
	var i = 1,
		len = arguments.length,
		target = arguments[0],
		j;
	//如果只有一个参数
	if(i == len){
		//源对象为当前对象
		target = this;
		i--;
	}
	for(; i < len; i++){
		for(j in arguments[i]){
			target[j] = arguments[i][j];
		}
	}
	return target;
}
//扩展A
A.extend(A, {ds: 123456});
//或var eDemo = A.extend({ds: 123456});
console.log(A.ds);

//扩展A.fn
A.fn.extend({dss: 124});
//或A.extend(A.fn, {get: function(){...; return this;}});
//return this是为了链式调用