dojo.mixin、dojo.extend、dojo.delegate解析

dojo.mixin

dojo.mixin函数签名为:function(/*Object*/obj, /*Object...*/props){;其中obj为目标对象,props为源对象,可以传入多个,该方法用于将其它对象中的属性(也包括函数属性)混入至目标对象,然后返回目标对象,如果混入源对象与目标对象同时存在某个属性时,则源对象属性会覆盖目标对象属性,但是并不会修改目标对象的prototype。


<script type="text/javascript">
	var a = {
		name : "zhangsan",
		address : "地球"
	};
	var b = {
		age : 18
	};
	var c = {
		address : "中国"	
	};
	
	//将b、c对象中的属性混入目标对象a
	var mixed = dojo.mixin(a, b, c);
	//输出为 Object { name="zhangsan",  address="中国",  age=18}
	//可以看到已包含三个属性,并且目标对象a的address属性被源对象c的相对属性覆盖了
	console.info(mixed);
	//结果为true,因为混入后目标对象被返回了,只是往目标对象中添加了属性,但是目标对象地址并没有发生改变
	console.info(mixed==a);
</script>

下面我们看一下dojo中的源码:

dojo.mixin = function(/*Object*/obj, /*Object...*/props){
	if(!obj){ obj = {}; }	//如果obj目标对象不存在,则赋予一个空对象,防止异常
	for(var i=1, l=arguments.length; i<l; i++){	//遍历混入源对象,注意索引从1开始,因为需要排除obj目标对象
		d._mixin(obj, arguments[i]);//调用真正实现混入的_mixin函数
	}
	//返回原来的目标对象
	return obj; // Object
}

var extraNames, extraLen, empty = {};
//如果toString(覆盖从Object继承的toString)不能在for..in循环中遍历到,则extraNames为undefined,如果能则赋值为空列表
for(var i in {toString: 1}){ extraNames = []; break; }
//如果extraNames存在则dojo._extraNames会等于extraNames,即是一个空列表
//如果extraNames为undefined,则dojo._extraNames为["hasOwnProperty", "valueOf", "isPrototypeOf", "propertyIsEnumerable", "toLocaleString", "toString", "constructor"]
dojo._extraNames = extraNames = extraNames || ["hasOwnProperty", "valueOf", "isPrototypeOf",
	"propertyIsEnumerable", "toLocaleString", "toString", "constructor"];
extraLen = extraNames.length;//获取长度

dojo._mixin = function(/*Object*/ target, /*Object*/ source){
	var name, s, i;
	
	//遍历源对象中的属性
	for(name in source){
		//在混入的时候需要排除从Object继承而来的属性,除非源对象重新定义了从Object继承而来的属性
		s = source[name];//取出属性值
		//成立条件有:
		//1. 目标对象中不存在源对象中的某个属性
		//2. 目标对象与源对象属性值不相等并且 (该属性不是从Object继承而来或者源对象重新定义了从Object继承而来的属性)
		if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
			//将源对象属性值赋给目标对象
			target[name] = s;
		}
	}
	
	// IE doesn't recognize some custom functions in for..in	有些版本的IE对于重新定义从Object继承来而的属性不能识别,所以需要重新判断一次
	if(extraLen && source){
		for(i = 0; i < extraLen; ++i){
			name = extraNames[i];
			s = source[name];
			if(!(name in target) || (target[name] !== s && (!(name in empty) || empty[name] !== s))){
				target[name] = s;
			}
		}
	}
	//返回目标对象
	return target; // Object
}

dojo.extend

dojo.extend函数签名为:function(/*Object*/ constructor, /*Object...*/ props); 接受一个构造函数和多个源对象。如果第一个参数不是一个构造函数,确切点说是不包含一个prototype属性。该函数用于将多个源对象中的属性混入到一个构造函数的prototype属性当中,最返回这个构造函数。该函数就是基于dojo.mixin实现的,一看源码便知:

dojo.extend = function(/*Object*/ constructor, /*Object...*/ props){
		// summary:
		//		Adds all properties and methods of props to constructor's
		//		prototype, making them available to all instances created with
		//		constructor.
	for(var i=1, l=arguments.length; i<l; i++){
		d._mixin(constructor.prototype, arguments[i]);
	}
	return constructor; // Object
};

因为混入的目标对象是构造函数的prototype属性,所以通过该构造函数创建(new)出来的对象会包含所有源对象中的属性。

由上可知,mixin适用于一次性混入,而extend适用于永久性混入(因为改为了prototype)

dojo.delegate

该函数调用后返回一个新对象,并且会对这个新对象的[[prototype]]属性混入新的属性,源码如下:
dojo.delegate = dojo._delegate = (function(){
	//临时构造函数
	function TMP(){}
	//返回一个匿名函数,该函数其实就是dojo.delegate函数
	return function(obj, props){
		TMP.prototype = obj;
		var tmp = new TMP();
		//虽然TMP.prototype重新置为null,但是tmp对象已经创建出来了,其[[prototype]]属性已经指向了obj,
		//所以通过tmp对象可以访问到obj对象中的属性
		TMP.prototype = null;
		//如果props存在,则将props混入tmp对象中,所以tmp对象中就有了props对象的所有属性
		if(props){
			d._mixin(tmp, props);
		}
		return tmp; // 返回tmp对象
	};
})();//立即执行

由上可知,dojo.delegate与dojo_delegate是一样的,指向了同一个函数对象。js中,每一个对象创建出来都会有一个[[prototype]]属性,也就是创建这个对象的构造函数的prototype属性,在FireFox中[[prototype]]属性可以通过__proto__来访问,请看下面的例子:
function Foo() {
	this.name = "Foo";
}
var foo = new Foo();
var de = dojo.delegate(foo, {address : "中国"});
console.info(de);	//Foo {address="中国", name="Foo"}
//因为在delegate函数中执行了TMP.prototype = obj;
console.info(de.__proto__==foo);	//true

PS:dojo版本为dojo-release-1.6.3

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值