jquery是什么有什么作用
jQuery中的extend()⽅法
通常我们使⽤jquery的extend时,⼤都是为了实现默认字段的覆盖,即若传⼊某个字段的值,则使⽤传⼊值,否则使⽤默认值。如下⾯的代码:
1function getOpt(option){
2var _default = {
3        name : 'wenzi',
4        age : '25',
5        sex : 'male'
6    }
7    $.extend(_default, option);
8return _default;
9 }
10 getOpt();  // {name: "wenzi", age: "25", sex: "male"}
11 getOpt({name:'bing'}); // {name: "bing", age: "25", sex: "male"}
12 getOpt({name:'bing', age:36, sex:'female'});  // {name: "bing", age: 36, sex: "female"}
那现在我们就得需要知道这个 extend 具体是怎么实现的了,除了实现上⾯的功能,还有其他作⽤么?那肯定是有的啦,否则我也不会问那句话了((⊙﹏⊙)b)。我们先来看看 extend 主要有哪些功能,然后再看实现这些功能的原理。
1. extend能实现的功能
其实从 extend 的含义⾥,我们就能知道 extend 是做什么的了。 extend 翻译成汉语后就是:延伸、扩展、推⼴。
1.1 将两个或更多对象的内容合并到第⼀个对象
我们来看看 $.extend() 提供的参数: d( target [, object1 ] [, objectN ] ) , extend ⽅法需要⾄少传⼊⼀个参数,第⼀个必需,后⾯的都是可选参数。若传给 extend 是两个或两个以上的参数都是对象类型,那么就会把后⾯所有对象的内容合并给 target (第⼀个对象)上。
我们再来看看上⾯的例⼦:
1function getOpt(option){
2var _default = {
3        name : 'wenzi',
4        age : '25',
5        sex : 'male'
6    }
7    `$.extend(_default, option);`
8return _default;
9 }
$.extend() 中接收了两个参数 _default 和 option ,那么 extend ⽅法执⾏时,就会把 option 对象上字段的值全给了 _default 。于
是 _default 上设置的默认值就会被option上的值覆盖。当然,若option上没有这个字段,就不会覆盖_default上字段的值。
上⾯函数中的extend,只是传⼊了两个参数,那传的参数再更多⼀些呢:
1function getOpt(target, obj1, obj2, obj3){
2    $.extend(target, obj1, obj2, obj3);
3return target;
4 }
5
6var _default = {
7    name : 'wenzi',
8    age : '25',
9    sex : 'male'
10 }
11var obj1 = {
12    name : 'obj1'
13 }
14var obj2 = {
15    name : 'obj2',
16    age : '36'
17 }
18var obj3 = {
19    age : '67',
20    sex : {'error':'sorry, I dont\'t kown'}
21 }
22 getOpt(_default, obj1, obj2, obj3);  // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}
这⾥我们传⼊了4个参数,然后 getOpt() 返回第⼀个参数的值。从运⾏的得到结果我们可以看到,属性值永远是最后⼀个属性的值。
还有很重要的⼀点, $.extend() 其实是有返回值的,返回的就是修改后的第⼀个参数的值。如我们可以把上⾯的函数修改成这样:
1function getOpt(target, obj1, obj2, obj3){
2var result = $.extend(target, obj1, obj2, obj3);
3return result; // // result即修改后的target值
4 }
若我们传⼊的参数不想被修改,我们可以⽤⼀个空对象来作为第⼀个参数,然后获取$.extend()的返回值:
1function getOpt(target, obj1, obj2, obj3){
2var result = $.extend({}, target, obj1, obj2, obj3);
3return result; // // result即为{}修改后的值
4 }
1.2 为JQUERY扩展⽅法或属性
刚才我们在1.1中讲的 $.extend() 的例⼦都是传了两个或两个以上的参数,但其实只有⼀个参数是必须的。若只传⼀个参数会怎样呢。
如果只有⼀个参数提供给 $.extend() ,这意味着⽬标参数被省略。在这种情况下, jQuery 对象本⾝被默认为⽬标对象。这样,我们可以
在 jQuery 的命名空间下添加新的功能。这对于插件开发者希望向  jQuery  中添加新函数时是很有⽤的。
1 $.extend({
2    _name : 'wenzi',
3    _getName : function(){
4return this._name;
5    }
6 })
7
8 $._name; // wenzi
9 $._getName(); // wenzi
这样我们就为jQuery扩展了 _name 属性和 _getName ⽅法。
1.3 深度拷贝和浅度拷贝
针对什么是深度拷贝,什么是浅度拷贝,我们先来看⼀个简单的例⼦。
1var obj = {name:'wenzi', sex:'male'};
2var obj1 = obj; // 赋值
3 obj1.name = 'bing';
4 console.log(obj.name); // bing
我们修改了obj1中的name值,结果obj中的值也跟着发⽣了变化,这是为什么呢。其实这就是浅度拷贝:这仅仅是将obj对象的引⽤地址简单的复制了⼀份给予变量 obj1,⽽并不是将真正的对象克隆了⼀份,因此obj和obj1指向的都是同⼀个地址。当修改obj1的属性或给obj1添加新属性时,obj都会受到影响。
可是如果变量的值不是对象和数组,修改后⾯的变量是不会影响到前⾯的变量:
1var s = 'hello';
2var t = s;
3 t = 'world';
4 console.log(s); // hello
那么深度拷贝就不是拷贝引⽤地址,⽽是实实在在的复制⼀份新对象给新的变量。在上⾯使⽤$.extend()中,都是使⽤的浅度拷贝,因此若后⾯的参数值是object类型或array类型,修改_default(target)的值,就会影响后⾯参数的值。
如我们使⽤ getOpt(_default, obj1, obj2, obj3) ;得到的 _default 值是 {name: “obj2”, age: “67”, sex: {error: “sorry, I dont’t kown”}} ,可是若:
_ = 'hello world';
那么 也会跟着修改,因为 obj3.sex 是⼀个 object 类型。
不过 $.extend() 也提供了深度拷贝的⽅法: d( [deep ], target, object1 [, objectN ] ) 。若第⼀个参数是boolean类型,且值
是true,那么就会把第⼆个参数作为⽬标参数进⾏合并。
1var obj = {name:'wenzi', score:80};
2var obj1 = {score:{english:80, math:90}}
3 $.extend(true, obj, obj1);
4 lish = 10;
5 console.log(lish);  // 10
6 console.log(lish);  // 80
执⾏后我们发现,⽆论怎么修改obj.score⾥的值,都不会影响到obj1.score了。
2. jQuery中extend实现原理
其实不看源码,对 extend ⼤致的过程应该也是了解的:对后⼀个参数进⾏循环,然后把后⾯参数上所有的字段都给了第⼀个字段,若第⼀个参数⾥有相同的字段,则进⾏覆盖操作,否则就添加⼀个新的字段。
下⾯是jQuery中关于 extend 的源码,我就在源码上进⾏注释讲解了,随后再在后⾯进⾏总结:
1// 为与源码的下标对应上,我们把第⼀个参数称为`第0个参数`,依次类推
d = d = function() {
3var options, name, src, copy, copyIsArray, clone,
4        target = arguments[0] || {}, // 默认第0个参数为⽬标参数
5        i = 1,    // i表⽰从第⼏个参数凯斯想⽬标参数进⾏合并,默认从第1个参数开始向第0个参数进⾏合并
6        length = arguments.length,
7        deep = false;  // 默认为浅度拷贝
8
9// 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false
10// 同时将第1个参数作为⽬标参数,i从当前⽬标参数的下⼀个
11// Handle a deep copy situation
12if ( typeof target === "boolean" ) {
13        deep = target;
14
15// Skip the boolean and the target
16        target = arguments[ i ] || {};
17        i++;
18    }
19
20//    判断⽬标参数的类型,若⽬标参数既不是object类型,也不是function类型,则为⽬标参数重新赋值
21// Handle case when target is a string or something (possible in deep copy)
22if ( typeof target !== "object" && !jQuery.isFunction(target) ) {
23        target = {};
24    }
25
26// 若⽬标参数后⾯没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'})
27// 则⽬标参数即为jQuery本⾝,⽽target表⽰的参数不再为⽬标参数
28// Extend jQuery itself if only one argument is passed
29if ( i === length ) {
30        target = this;
31        i--;
32    }
33
34// 从第i个参数开始
35for ( ; i < length; i++ ) {
36// 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true,37// 因此可以⽤null来同时过滤掉null和undefind
38// ⽐如$.extend(target, {}, null);中的第2个参数null是不参与合并的
39// Only deal with non-null/undefined values
40if ( (options = arguments[ i ]) != null ) {
41
42// 使⽤for~in获取该参数中所有的字段
43// Extend the base object
44for ( name in options ) {
45                src = target[ name ];  // ⽬标参数中name字段的值
46                copy = options[ name ]; // 当前参数中name字段的值
47
48// 若参数中字段的值就是⽬标参数,停⽌赋值,进⾏下⼀个字段的赋值
49// 这是为了防⽌⽆限的循环嵌套,我们把这个称为,在下⾯进⾏⽐较详细的讲解
50// Prevent never-ending loop
51if ( target === copy ) {
52continue;
53                }
54
55// 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进⾏深度赋值
56// Recurse if we're merging plain objects or arrays
57if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {
58// 若当前参数中name字段的值为Array类型
59// 判断⽬标参数中name字段的值是否存在,若存在则使⽤原来的,否则进⾏初始化
60if ( copyIsArray ) {
61                        copyIsArray = false;
62                        clone = src && jQuery.isArray(src) ? src : [];
63
64                    } else {
65// 若原对象存在,则直接进⾏使⽤,⽽不是创建
66                        clone = src && jQuery.isPlainObject(src) ? src : {};
67                    }
68
69// 递归处理,此处为2.2
70// Never move original objects, clone them
71                    target[ name ] = d( deep, clone, copy );
72
73// deep为false,则表⽰浅度拷贝,直接进⾏赋值
74// 若copy是简单的类型且存在值,则直接进⾏赋值
75// Don't bring in undefined values
76                } else if ( copy !== undefined ) {
77// 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性
78                    target[ name ] = copy;
79                }
80            }
81        }
82    }
83
84// 返回修改后的⽬标参数
85// Return the modified object
86return target;
87 };
源码分析完了,下⾯我们来讲解下源码中存在的⼏个难点和重点。
2.1 若参数中字段的值就是⽬标参数,停⽌赋值
在源码中进⾏了⼀下这样的判断:
1// Prevent never-ending loop
2if ( target === copy ) {
3continue;
4 }
为什么要有这样的判断,我们来看⼀个简单的例⼦,如果没有这个判断会怎么样:
1var _default = {name : 'wenzi'};
2var obj = {name : _default}
3 $.extend(_default, obj);
4 console.log(_default);
输出的_default是什么呢:
1 _default = {name : _default};
_default是object类型,⾥⾯有个字段name,值是_default,⽽_default是object类型,⾥⾯有个字段na
me,值是_default……,⽆限的循环下去。于是jQuery中直接不进⾏操作,跳过这个字段,进⾏下⼀个字段的操作。
2.2 深度拷贝时进⾏递归处理
我们在前⾯稍微的讲解了⼀下,变量值为简单类型(如number, string, boolean)进⾏赋值时是不会影响上⼀个变量的值的,因此,如果当前字段的值为 Object 或 Array 类型,需要对其进⾏拆分,直到字段的值为简单类型(如number, string, boolean)时才进⾏赋值操作。
3. $.extend()与$.fn.extend()
上⾯讲解的全都是 $.extend() ,根本就没讲 $.fn.extend() 。可是,你有没有发现⼀个细节,在这段代码的第⼀⾏是怎么写的:
也就是说 $.extend() 与 $.fn.extend() 共⽤的是同⼀个函数体,所有的操作都是⼀样的,只不过两个 extend 使⽤的对象不同罢
了: $.extend() 是在 jQuery($) 上进⾏操作的;⽽ $.fn.extend() 是在jQuery对象上进⾏操作的,如 $(‘div’).extend() 。
4. 总结
这就是jQuery中extend的实现,以后若我们需要⽤到上⾯的功能时,除了使⽤$.extend(),我们也可以在不引⼊jQuery框架的情况下,⾃⼰写⼀个简单的extend()来实现上⾯的功能。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。