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.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 = 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 };
由上可知,mixin适用于一次性混入,而extend适用于永久性混入(因为改为了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对象 }; })();//立即执行
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