title: 解读jQuery中extend函数 categories:
$.extend.apply( null, [ true, { "a" : 1, "b" : 2 } ] );//console.log(window.a);//window.location.reload();
$.extend.apply( null, [ true, { "a" : 1, "b" : 2 } ].concat( { "c" : 3, "d" : 4 } ) );
//console.log(window.a)
<p><strong>一、问题:</strong></p>
<p> 1. null在这里是干啥?</p>
<p> 2. window.a分别是什么?</p><p><strong>二、我们先一起来了解下jQuery中的extend函数</strong></p>
<p> 在jQuery-V1.2.6中:</p>
jQuery.extend = jQuery.fn.extend = function() {
// copy reference to target object
var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
// Handle a deep copy situation
if ( target.constructor == Boolean ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target != "object" && typeof target != "function" )
target = {};
// extend jQuery itself if only one argument is passed
if ( length == i ) {
target = this;
--i;
}
for ( ; i < length; i++ )
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null )
// Extend the base object
for ( var name in options ) {
var src = target[ name ], copy = options[ name ];
// Prevent never-ending loop
if ( target === copy )
continue;
// Recurse if we're merging object values
if ( deep && copy && typeof copy == "object" && !copy.nodeType )
target[ name ] = jQuery.extend( deep,
// Never move original objects, clone them
src || ( copy.length != null ? [ ] : { } )
, copy );
// Don't bring in undefined values
else if ( copy !== undefined )
target[ name ] = copy;
}
// Return the modified object
return target;
};
jQuery - v1.2.6 extend
<p>在jQuery-V1.8.2中:</p>
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[0] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
target = arguments[1] || {};
// skip the boolean and the target
i = 2;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
target = {};
}
// extend jQuery itself if only one argument is passed
if ( length === i ) {
target = this;
--i;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( (options = arguments[ i ]) != null ) {
// Extend the base object
for ( name in options ) {
src = target[ name ];
copy = options[ name ];
// Prevent never-ending loop
if ( target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))){
if ( copyIsArray ) {
copyIsArray = false;
clone = src && jQuery.isArray(src) ? src : [];
} else {
clone = src && jQuery.isPlainObject(src) ? src : {};
}
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery - V1.8.2 extend
<p> 比较两个版本的jQuery,extend函数总体构架上基本没有变化,高版本中写代码更加规范了,很多var变量都前置(这是比较好的编码习惯,当然,也是为了方便压缩工具对代码进行压缩)。</p>
<p>jQuery.fn.extend就是把extend函数绑定到他的原型链中。这样一来,既可以作为静态函数在$上直接引用($.extend),也可以在$(obj)上使用extend。</p>
<ul>
<li><a href="http://api.jquery.com/jQuery.extend/" target="_blank">jQuery.extend() API文档</a></li>
<li><a href="http://api.jquery.com/jQuery.fn.extend/" target="_blank">jQuery.fn.extend() API文档</a></li>
</ul>
<p><em>注意,如果函数没有在原型链上绑定,是不能被\继承"的!</em></p><p>代码大概的意思就是:</p> 第一个参数是boolean类型 ---------> 深度递归复制
|
|
---------> 如果只有一个参数(除第一个boolean)---------> 将函数的this环境extend进去
|
|
---------> 将后面的参数extend到\第一个"参数中 ---------> 返回\第一个"参数
<p><strong>三、问题解释</strong></p>
<ul>
<li><strong> 第一个问题中,</strong></li>
</ul>
```
$.extend.apply( null, [ true, { "a" : 1, "b" : 2 } ] );
```
<p>extend作为一个静态函数被调用,null被绑定,但是因为满足\只有一个"参数(boolean除外)的条件 , 将函数的this环境(window)extend进去,return的对象就是window对象,所以得到的结果是</p>window
<p><span>即,window.a = 1</span></p>
<p> <img src="https://images.cnitblog.com/blog/387325/201307/20134313-96862ff8cfa84a72a7ef6ab81b6d66a6.jpg" alt=""></p>
<ul>
<li><strong><span>第二个问题中,</span></strong></li>
</ul>
$.extend.apply( null, [ true, { "a" : 1, "b" : 2 } ].concat( { "c" : 3, "d" : 4 } ) );
<p>相当于传入三个参数,第一个是true,第二个是 匿名对象{ "a" : 1, "b" : 2 },第三个是匿名对象{ "c" : 3, "d" : 4 }, 此时的this环境是null(因为将函数绑定到null上面了)。</p>
<p>那么结果就是{ "a" : 1, "b" : 2, "c" : 3, "d" : 4 }, 此刻并不能在window中索引到a这个属性</p>
<p><img src="https://images.cnitblog.com/blog/387325/201307/20134220-8b0da1f1b68c41d190e65c9925dca2c4.jpg" alt=""></p>
<p>如要想要访问,那便是null.a,但这种访问方式肯定是不对的。</p>
<p>由于没有变量来接收这个返回的值,所以被作为垃圾给回收了。</p>
<p>有兴趣的童鞋可以试试这个:</p>
$.extend.apply( $, [ true, { "a" : 1, "b" : 2 } ] ); $.extend.apply( $, [ true, { "a" : 1, "b" : 2 } ].concat( { "c" : 3, "d" : 4 } ) );
```
<p>把$作为当前的环境,看看a被绑定在那个元素上了~</p><p><strong> 四、小结</strong></p> <p> jQuery是一个非常优秀的JS库,也是前辈们学习JS后经验的总结和思想的结晶,从jQuery1.2版本到现在的2.0版本,代码风格上、函数处理方式上有比较明显的改变,很值得花些功夫去研究。学习的过程中多看看ta们的编码风格、编码规范,了解库的整体构架和实现原理,这样应该会有比较大的提升~</p> <p> 我觉得前端这方面想独树一帜,就必须在代码中体现自己的思想。</p>