专栏首页前端一会jQuery源码研究:jQuery对象及原型上的extend()方法

jQuery源码研究:jQuery对象及原型上的extend()方法

现在看到jQuery的227行,本篇读jQ的继承方法jQuery.extend()

官方作用解释是将一个或多个对象合并到目标对象中。

jQuery.extend( [deep ], target, object1 [, objectN ] )

  • 其中deep是布尔类型,如为true,则执行深拷贝,即合并成为递归;
  • target是一个对象扩展,如果附加的对象被传递给这个方法将那么它将接收新的属性,如果它是唯一的参数将扩展jQuery的命名空间;
  • 后面的object1objectN同样作为对象,包含额外的属性合并到第一个参数。

看下源码实现:

jQuery.extend = jQuery.fn.extend = function(){
    //方法体...
    var options, name, src, copy, copyIsArray, clone,
        target = arguments[ 0 ] || {},
        i = 1,
        length = arguments.length,
        deep = false;

    if ( typeof target === "boolean" ) {
        deep = target;

        target = arguments[ i ] || {};
        i++;
    }

    if ( typeof target !== "object" && !isFunction( target ) ) {
        target = {};
    }

    if ( i === length ) {
        target = this;
        i--;
    }

    for ( ; i < length; i++ ) {

        if ( ( options = arguments[ i ] ) != null ) {

            for ( name in options ) {
                src = target[ name ];
                copy = options[ name ];

                if ( target === copy ) {
                    continue;
                }

                if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
                    ( copyIsArray = Array.isArray( copy ) ) ) ) {

                    if ( copyIsArray ) {
                        copyIsArray = false;
                        clone = src && Array.isArray( src ) ? src : [];

                    } else {
                        clone = src && jQuery.isPlainObject( src ) ? src : {};
                    }

                    target[ name ] = jQuery.extend( deep, clone, copy );

                } else if ( copy !== undefined ) {
                    target[ name ] = copy;
                }
            }
        }
    }

    // 返回修改后的对象
    return target;
}

jQuery对象上添加extend属性,并且在jQuery.fn上面也添加同样的extend属性,还记得前面jQuery.fn = jQuery.prototype不?jQuery对象的fn属性指针就指向jQuery对象的原型,并且因为对象都是引用类型的,所以上例代码的操作意思就是:在jQuery对象和它的原型对象上都添加extend方法,该方法最后返回的是一个合并处理后的对象。

jQuery对象上绑定的extend()jQuery.fn上绑定的extend()方法其实是不同的,前者是类方法,是静态方法,调用方法写作$.extend();后者是实例方法,是成员方法,调用方法写作$(selector).extend()

extend()方法中,首先定义了一些初始变量:

var options, name, src, copy, copyIsArray, clone,
        target = arguments[ 0 ] || {},
        i = 1,
        length = arguments.length,
        deep = false;

deep作为布尔类型值表明是否深度拷贝对象,如为true,且多个对象的某个同名属性也都是对象,则该"属性对象"的属性也将进行合并。target就是最后准备返回的一个对象,定义时被赋予初始值对象,arguments[ 0 ] || {}指如参数数组有值则返回参数数组索引为0的值,否则就是返回一个空对象给target变量。

接下来是首个传参为布尔值进行处理,如true则执行深拷贝,并将第二个参数赋值给target对象:

if ( typeof target === "boolean" ) {
    deep = target;

    target = arguments[ i ] || {};
    i++;
}

当传入extend方法的第一个参数为布尔类型时,如存在传入第二个参数,则获取当前索引加1的参数并赋值给target,或者参数取值为假时,直接将||符号右边的空对象{}赋值给target

然后就是对target值为非对象类型的情况进行处理:

if(typeof target !== 'object' && !isFunction(target)){
    target = {};
}

targetstring类型或其他基本类型值或者是函数类型时,将target值直接用空对象赋值。

处理完不合适的参数类型,接下来就要进行方法本身逻辑了,先来个简单的:

if(i === length){
    target = this;
    i--;
}

i === length为真的情况,表示传参只传了一个对象参数,则方法return出来的target就是jQuery这个类对象本身。通过这种方式,可以为全局对象jQuery扩展新的方法:

$.extend({  //添加新的类方法
    sum: function(a, b){    
        return a + b;
    }
})

// 或者
$.fn.extend({    //添加新的实例方法
    diff: function(c, d){
        return c - d;
    }
})

这种功能在使用jQuery开发新的插件时,就非常有用了。

接下来就是extend方法的主要逻辑块了,其只处理值为非null和非undefined的情况,具体代码解释下看注释:

for ( ; i < length; i++ ) {

    // 只处理非null非undefined值
    // tips: 这个有个小技巧,undefined == null 值为true; 但undefined === null值为false。所以通过 !=null 这个操作,就可以直接屏蔽掉 null和undefined两种情况了。
    // 通过for循环将每个传入的参数赋值给变量 options
    if ( ( options = arguments[ i ] ) != null ) {

        // 扩展基对象
        for ( name in options ) {
            src = target[ name ];
            copy = options[ name ];

            // 防止死循环操作,如果全等,直接跳出
            if ( target === copy ) {    
                continue;
            }

            // 当合并纯对象或数组时进行递归操作。所谓纯对象,指的就是普通的键值对形式构成的对象
            // 当deep为true意为执行深拷贝,且copy对象为纯对象  或  copy对象为数组 Array.isArray()用于确定传递值是否为数组,返回一个布尔值
            if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
                ( copyIsArray = Array.isArray( copy ) ) ) ) {   

                if ( copyIsArray ) {    //如果为数组,则将数组赋值给clone变量,否则就将对象赋值给clone变量
                    copyIsArray = false;
                    clone = src && Array.isArray( src ) ? src : [];

                } else {
                    clone = src && jQuery.isPlainObject( src ) ? src : {};
                }

                // 这里是确保不影响原对象,只是克隆它们
                target[ name ] = jQuery.extend( deep, clone, copy );

            // 确保不会操作到undefined值
            } else if ( copy !== undefined ) {
                target[ name ] = copy;
            }
        }
    }
}

以上就是jQuery对象和jQuery.fn即原型对象上添加extend()方法的代码解释,再复习下:jQuery对象和其原型上都具有extend()方法,区别在于一个是类方法,一个是成员方法,在使用场景上请注意。

本文分享自微信公众号 - 前端小二(frontendxiao2),作者:小二君

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-12-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • jQuery源码研究:化繁为简之拎出框架结构

    昨天看的是jQuery源码中最顶部的模块规范判断部分,其主要作用是针对所处不同环境支持的模块规范给出兼容性操作。而jQuery真正主体的部分是在工厂函数中的,在...

    前端_AWhile
  • javascript设计模式五:原型模式

    在javascript语言中,原型与原型链是一个非常重要的概念,因为它们是javascript语言得以成立的根本。因为javascript是基于原型的面向对象编...

    前端_AWhile
  • jQuery源码研究:为jQ对象扩展的一些工具方法(上)

    上一章,讨论的是jQuery对象及其原型上的extend()方法,在源码中,实现了支持开发者自行扩展新方法的功能,但其实jQuery也通过对extend()传入...

    前端_AWhile
  • 【前端面试】字节跳动2019校招面经 - 前端开发岗(二)

    querySelectorAll()返回的是DOM原生element对象 而jQuery的选择器返回的是jQuery的包装对象,同时包含了原生DOM对象和一些j...

    CloudCat
  • 从手机App到网点交互请求的日志记录

    首先找一连串的*****************************, 这个醒目的标志代表一个新的从KOI App发起的请求。

    Jerry Wang
  • jQuery Builder:jQuery 库的精简之道

    最近在做一个手机主题,为了用上看似华丽的Ajax 特效,不得不用上jQuery(不要问我为什么不用原生js,要是我会写就不用那么费劲了)。但众所周知Jquery...

    Jeff
  • jQuery:详解jQuery中的事件(一)

    之前用过一些jQuery的动画和特效,但是用到的部分也不超过10%的样子,感觉好浪费啊——当然浪费的不是jQuery,而是Web资源。后来就想深入研究下jQue...

    王金龙
  • 采购中的高级分析方法

    原文地址:https://dzone.com/articles/advanced-analytics-in-procurement

    大数据弄潮儿
  • Hyperledger Fabric 积分代币上链方案

    中国广东省深圳市龙华新区民治街道溪山美地 518131 +86 13113668890 <netkiller@msn.com>

    netkiller old
  • 三分钟深入TT猫之故障转移

    结束了一周繁忙的工作,趁着周末,小编手中的键盘早已饥渴难耐了,想知道上期省略号中发生了什么有趣的故事么?且听小编娓娓道来,结尾有彩蛋。 ? 风月前场 春风再续,...

    小柒2012

扫码关注云+社区

领取腾讯云代金券