热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

对jQuery.extend()方法的分析

jQuery.extend方法是我们常用的方法,也是jQuery源码中的基础方法。它的主要作用是:将一个或多个“源对象”合并到一个“目标对象”中,并返回目标对象。它主要有三种表现形式:a、jQue

jQuery.extend方法是我们常用的方法,也是jQuery源码中的基础方法。它的主要作用是:将一个或多个“源对象”合并到一个“目标对象”中,并返回目标对象。它主要有三种表现形式:

a、jQuery.extend(destination, source1, source2, source3 ....)

b、jQuery.extend( source )

c、jQuery.extend(boolean, destination, source1, source2, source3 ....)

a方式第一个参数作为“目标对象”,其它参数作为“源对象”。

b方式只有一个参数,这里的这个参数变成了“源对象”,“目标对象”变成了jQuery。说白了就是"源对象"的属性,变成jQuery函数的静态方法或属性。

c方式的第一个参数是boolean类型的,第二个参数是"目标对象",剩下的参数是“源对象”。当第一个参数的值为true时,表示对象合并时支持“深拷贝”。

知道了函数的用法,我们肯定好奇jQuery是怎么实现的,想看看jQuery的源码。不过在看jQuery源码之前,我们不妨试着写写这个方法的功能,然后在回过头来看jQuery源码,感受可能更深,看到的东西可能越多。

我们先不要给自己压力,先从最简单的开始,要实现的方法就两个参数:第一个参数是:“目标对象”,第二个参数是:“源对象”。先实现把“源对象”合并到“目标对象”中。代码如下:

var Test = function(){}
Test.extend0 = function(destination, source){
    for(var key in source){
        destination[key] = source[key]
    }
    return destination
}

第二步实现可以传入多个参数,第一个参数是目标对象,其他参数是源对象。代码如下:

Test.extend1 = function(){
    var destination = arguments[0]
    var sourceArr = Array.prototype.slice.call(arguments,1)
    for(var i = 0, len = sourceArr.length; i ){
        var source = sourceArr[i]
        for(var key in source){
            destination[key] = source[key]
        }
    }
    return destination
}

第三步实现只有一个参数时,将参数对象的属性附加给Test。代码如下:

Test.extend2 = function(){
    var argumentsLen = arguments.length
    if( argumentsLen === 1 ){
        var source = arguments[0]
        for(var key in source){
            Test[key] = source[key]
        }
    }else{
        var destination = arguments[0]
        var sourceArr = Array.prototype.slice.call(arguments,1)
        for(var i = 0, len = sourceArr.length; i ){
            var source = sourceArr[i]
            for(var key in source){
                destination[key] = source[key]
            }
        }
        return destination
    }
}

第四步实现“深拷贝”,第一个参数是是否进行深拷贝的布尔判断,第二个参数是目标对象,其他参数是源对象。代码如下:

Test.extend3 = function(){
    var argumentsLen = arguments.length
    if( argumentsLen === 1 ){
        var source = arguments[0]
        for(var key in source){
            Test[key] = source[key]
        }
    }else{
        var firstItem = arguments[0]
        var isBoolean = typeof firstItem === "boolean"
        var destination = isBoolean ? arguments[1] : firstItem
        var startNum = isBoolean ? 2 : 1
        var sourceArr = Array.prototype.slice.call(arguments,startNum)
        for(var i = 0, len = sourceArr.length; i ){
            var source = sourceArr[i]
            if( isBoolean ){
                deepExtend( destination, source )
            }else{
                for(var key in source){
                    destination[key] = source[key]
                }
            }
        }
        return destination
    }
}

function deepExtend(destination, source){
    for(var key in source){
        var value = source[key]
        if( value instanceof Array ){
            destination[key] = arguments.callee.call( destination[key] || [], value )
        }else if( value instanceof Object ){
            destination[key] = arguments.callee.call( destination[key] || {}, value )
        }else{
            destination[key] = source[key]                
        }
    }
    return destination
}

好了,我们按照自己的思路,粗略的实现了自己的extend方法,现在就看下jQuery对extend的实现,对比学习一下。源码如下:

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

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {
        deep = target;

        // skip the boolean and the target
        target = arguments[ i ] || {};
        i++;
    }

    // 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 ( i === length ) {
        target = this;
        i--;
    }

    for ( ; 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;
}

通过对比,我们发现:

a、jQuery在代码组织和实现上更加优雅。

b、jQuery考虑到了一些特殊情况。比如:

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

这是为了避免无限循环,“源对象”的属性指向的是“目标对象”,当合并对象时,也就是将“自己”复制为“自己的属性”。这是不可取的。

c、jQuery在数组(jQuery.isArray)和“纯粹对象”(jQuery.isPlainObject)的判断上,考虑的更精细。

先自己想思路去实现,再反过来对比学习,这种学习方法感觉挺好的。a、加强了独立思考能力。b、发现新的学习内容。c、暴漏自己的不足。

 


推荐阅读
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • C++程序员视角下的Rust语言
    自上世纪80年代初问世以来,C就是一门非常重要的系统级编程语言。到目前为止,仍然在很多注重性能、实时性、偏硬件等领域发挥着重要的作用。C和C一样&#x ... [详细]
  • 开发笔记:冷知识:达夫设备(Duff's Device)效率真的很高吗?
    本文由编程笔记#小编为大家整理,主要介绍了冷知识:达夫设备(Duff'sDevice)效率真的很高吗?相关的知识,希望对你有一定的参考价值。ID:技术让梦想更伟大 ... [详细]
  • 本文讨论了在手机移动端如何使用HTML5和JavaScript实现视频上传并压缩视频质量,或者降低手机摄像头拍摄质量的问题。作者指出HTML5和JavaScript无法直接压缩视频,只能通过将视频传送到服务器端由后端进行压缩。对于控制相机拍摄质量,只有使用JAVA编写Android客户端才能实现压缩。此外,作者还解释了在交作业时使用zip格式压缩包导致CSS文件和图片音乐丢失的原因,并提供了解决方法。最后,作者还介绍了一个用于处理图片的类,可以实现图片剪裁处理和生成缩略图的功能。 ... [详细]
  • 本文介绍了使用哈夫曼树实现文件压缩和解压的方法。首先对数据结构课程设计中的代码进行了分析,包括使用时间调用、常量定义和统计文件中各个字符时相关的结构体。然后讨论了哈夫曼树的实现原理和算法。最后介绍了文件压缩和解压的具体步骤,包括字符统计、构建哈夫曼树、生成编码表、编码和解码过程。通过实例演示了文件压缩和解压的效果。本文的内容对于理解哈夫曼树的实现原理和应用具有一定的参考价值。 ... [详细]
  • Ihaveaworkfolderdirectory.我有一个工作文件夹目录。holderDir.glob(*)>holder[ProjectOne, ... [详细]
  • 本文介绍了在满足特定条件时如何在输入字段中使用默认值的方法和相应的代码。当输入字段填充100或更多的金额时,使用50作为默认值;当输入字段填充有-20或更多(负数)时,使用-10作为默认值。文章还提供了相关的JavaScript和Jquery代码,用于动态地根据条件使用默认值。 ... [详细]
  • PHP反射API的功能和用途详解
    本文详细介绍了PHP反射API的功能和用途,包括动态获取信息和调用对象方法的功能,以及自动加载插件、生成文档、扩充PHP语言等用途。通过反射API,可以获取类的元数据,创建类的实例,调用方法,传递参数,动态调用类的静态方法等。PHP反射API是一种内建的OOP技术扩展,通过使用Reflection、ReflectionClass和ReflectionMethod等类,可以帮助我们分析其他类、接口、方法、属性和扩展。 ... [详细]
  • 获取ul中第一个li元素的五种方法和多个ul中第一个li元素的四种方法
    本文介绍了获取ul中第一个li元素的五种方法和多个ul中第一个li元素的四种方法,包括使用jQuery的选择器和遍历方法。通过这些方法,可以方便地获取到所需的元素,并进行相应的操作。 ... [详细]
  • ps:写的第一个,不足之处,欢迎拍砖---只是想用自己的方法一步步去实现一些框架看似高大上的小功能(比如说模型中的toArraytoJsonsetAtt ... [详细]
  • angular.element使用方法及总结
    2019独角兽企业重金招聘Python工程师标准在线查询:http:each.sinaapp.comangularapielement.html使用方法 ... [详细]
  • jqueryajax怎么通过header传递参数?
    /这个是全局的ajax请求头设置,所有的ajax请求都会加上这个请求头 ... [详细]
  • 某天看jQuey的deffered对象的时候,突然想起了曾经面试的一个关于ajax的问题,就是同时发送三个ajax请求,当三个请求都成功的时候输出1,当时不知道jQuery的$.w ... [详细]
  • Git GitHub多人协作
    在学校做一个小项目需要多人协作,就用到了gitHub,百度了一下多数写得乱七八糟或者支离破碎,于是总结了一下自己的步骤如下,第一次使用GitHUb,哪里不对望大神指出一.前期准备: ... [详细]
  • 二十二、D3饼图Abstract在前一章中,你已经看到了条形图是如何表示某一类数 ... [详细]
author-avatar
康话口儿_536
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有