jquery之extend解析

    xiaoxiao2021-03-25  65

     jquery 之 extend 解析

    一、extend能实现的功能

    1、extend简介

       extend方法被挂载在了jQuery和jQuery.fn两个不同对象上,但是两者的内部代码实现确实相同的,只是功能不太一样。

    <1>jQuery.extend(object)

    用于将一个或多个对象的内容合并到目标对象。该函数可以将一个或多个对象的成员属性和方法复制到指定的对象上。该函数属于全局jQuery对象。

    jQuery.extend( target [, object1 ] [, objectN ] ),extend方法需要至少传入一个参数,第一个必需,后面的都是可选参数。若传给extend是两个或两个以上的参数都是对象类型,那么就会把后面所有对象的内容合并给target(第一个对象)上。

    <2>jQuery.fn.extend(object)

        用于为jQuery扩展一个或多个实例属性和方法(主要用于扩展方法)。jQuery.fn是jQuery的原型对象,其extend()方法用于为jQuery的原型添加新的属性和方法。这些方法可以在jQuery实例对象上调用。该函数属于jQuery的原型对象(jQuery.fn)。

     

    例如:

     function getOpt(option){         var _default = {                  name : 'wenzi',                  age : '25',                  sex : 'male'          }             $.extend(_default, option);`             return _default; } /*---console.log(JSON.stringify(getOpt()))---*/ getOpt();  // {name: "wenzi", age: "25", sex: "male"} getOpt({name:'bing'}); // {name: "bing", age: "25", sex: "male"} getOpt({name:'bing', age:36, sex:'female'});  // {name: "bing", age: 36, sex: "female"} function getOpt(target, obj1, obj2, obj3){ $.extend(target, obj1, obj2, obj3);        return target;    } //注:$.extend()返回修改后的第一个参数的值 var _default = {     name : 'wenzi',     age : '25',     sex : 'male' } var obj1 = {     name : 'obj1' } var obj2 = {     name : 'obj2',     age : '36' } var obj3 = {     age : '67', sex : {'error':'sorry, I dont\'t kown'}   } getOpt(_default, obj1, obj2, obj3);  // {name: "obj2", age: "67", sex: {error: "sorry, I dont't kown"}}

    结果:属性值永远是最后一个属性的值,但是这样_default就会被修改了。当然很多时候为了传入的参数不被修改,通常都会这么做,即传个空对象  $.extend({},target, obj1, obj2, obj3);则合并的目标对象即为{},不会去修改参数对象了。  

    2、为jQuery扩展方法或者属性

       $.extend()其实只有一个参数是必须的。如果只有一个参数提供给$.extend(),这意味着目标参数被省略。在这种情况下,jQuery对象本身被默认为目标对象[后面源码中看了就知道了]。这样,我们可以在jQuery的命名空间下添加新的功能。

    例如:

    $.extend({ _name : 'hello world', _getName : function(){ return this._name; } }) $._name; // hello world $._getName(); // hello world //这样我们就为jQuery扩展了_name属性和_getName方法。

    3、深度拷贝和浅度拷贝

    例如:

    var obj = {name:'星辰', sex:'male'}; var obj1 = obj; // 赋值 obj1.name = '小星辰'; console.log(obj.name); // 小星辰

       我们修改了obj1中的name值,结果obj中的值也跟着发生了变化,这是为什么呢。其实这就是浅度拷贝:这仅仅是将obj对象的引用地址简单的复制了一份给予变量 obj1,而并不是将真正的对象克隆了一份,因此obj和obj1指向的都是同一个地址。当修改obj1的属性或给obj1添加新属性时,obj都会受到影响。

    例如:

    var s = 'hello'; var t = s; t = 'world'; 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”}},可是若:_default.sex.error = 'hello world';那么obj3.sex.error也会跟着修改,因为obj3.sex是一个object类型。

    不过$.extend()也提供了深度拷贝的方法:jQuery.extend( [deep ], target, object1 [, objectN ] )。若第一个参数是boolean类型,且值是true,那么就会把第二个参数作为目标参数进行合并。

    例如:

    var obj = {name:'星辰', score:80}; var obj1 = {score:{english:80, math:90}} $.extend(true, obj, obj1); obj.score.english = 10; console.log(obj.score.english);   // 10 console.log(obj1.score.english);  // 80  这里并没有因为obj的改变而改变

     

    二、jQuery中extend能实现的原理

    1、源码解析

    // 为与源码的下标对应上,我们把第一个参数称为`第0个参数`,依次类推 jQuery.extend = jQuery.fn.extend = function() { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, // 默认第0个参数为目标参数 i = 1,    // i表示从第几个参数凯斯想目标参数进行合并,默认从第1个参数开始向第0个参数进行合并 length = arguments.length, deep = false;  // 默认为浅度拷贝   // 判断第0个参数的类型,若第0个参数是boolean类型,则获取其为true还是false // 同时将第1个参数作为目标参数,i从当前目标参数的下一个 // Handle a deep copy situation if ( typeof target === "boolean" ) { deep = target;   // Skip the boolean and the target target = arguments[ i ] || {}; i++; }   // 判断目标参数的类型,若目标参数既不是object类型,也不是function类型,则为目标参数重新赋值 // Handle case when target is a string or something (possible in deep copy) if ( typeof target !== "object" && !jQuery.isFunction(target) ) { target = {}; }   // 若目标参数后面没有参数了,如$.extend({_name:'wenzi'}), $.extend(true, {_name:'wenzi'}) // 则目标参数即为jQuery本身,而target表示的参数不再为目标参数 // Extend jQuery itself if only one argument is passed if ( i === length ) { target = this; i--; }   // 从第i个参数开始 for ( ; i < length; i++ ) { // 获取第i个参数,且该参数不为null和undefind,在js中null和undefined,如果不区分类型,是相等的,null==undefined为true, // 因此可以用null来同时过滤掉null和undefind // 比如$.extend(target, {}, null);中的第2个参数null是不参与合并的 // Only deal with non-null/undefined values if ( (options = arguments[ i ]) != null ) { // 使用for~in获取该参数中所有的字段 // Extend the base object for ( name in options ) { src = target[ name ];   // 目标参数中name字段的值 copy = options[ name ]; // 当前参数中name字段的值   // 若参数中字段的值就是目标参数,停止赋值,进行下一个字段的赋值 // 这是为了防止无限的循环嵌套,我们把这个称为,在下面进行比较详细的讲解 // Prevent never-ending loop if ( target === copy ) { continue; }   // 若deep为true,且当前参数中name字段的值存在且为object类型或Array类型,则进行深度赋值 // Recurse if we're merging plain objects or arrays if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) { // 若当前参数中name字段的值为Array类型 // 判断目标参数中name字段的值是否存在,若存在则使用原来的,否则进行初始化 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 );   // deep为false,则表示浅度拷贝,直接进行赋值 // 若copy是简单的类型且存在值,则直接进行赋值 // Don't bring in undefined values } else if ( copy !== undefined ) { // 若原对象存在name属性,则直接覆盖掉;若不存在,则创建新的属性 target[ name ] = copy; } } } }   // 返回修改后的目标参数 // Return the modified object return target; };  

    2、jquery扩展方式

        jquery为开发插件提供了两个方法.jQuery.extend(object); 为扩展jQuery类本身,为自身添加新的方法。jQuery.fn.extend(object);给jQuery对象添加方法。

        在源码中我们看到jQuery.extend = jQuery.fn.extend = function(){}。也就是说$.extend()与$.fn.extend()共用的是同一个函数体,所有的操作都是一样的,只不过两个extend使用的对象不同罢了。

    转载请注明原文地址: https://ju.6miu.com/read-34183.html

    最新回复(0)