jquery源码学习(一):自己实现一个简单的深复制函数

jquery源码分析

jquery$(selector).bar()调用方法的实现

$(selector)需要返回一个利用selector初始化的实例,并且这个实例能够访问jquery的原型方法,并且不使用new操作符。

实现这两步,需要:

  1. 构造函数$需要返回一个用new操作符调用的构造函数init的实例
  2. 将构造函数init的prototype属性设置为jQuery的prototype属性

我们可以这样做:

var $ = function(selector,context){
    *return new init();
}

$.prototype = {
    foo:function();
    bar:xxx;
}

function init(){
    ...;
}

*init.prototype = $.prototype

var something = $(selector);

但是在jquery中,init函数是在$.prototype内部的,因此带星号的语句需要修改为:

return new $.prototype.init();

$.prototype.init.prototype = $.prototype;

jquery的源码则是

return new jQuery.fn.init( selector, context, rootjQuery );//fn为jquery.prototype的一个引用。

jquery链式调用

在所有的方法最后添加return this即可实现链式调用。

jquery extent函数

extent函数源码分析

jQuery.extend = jQuery.fn.extend = function() {
    var src, copyIsArray, copy, name, options, clone,
        target = arguments[0] || {},    // 常见用法 jQuery.extend( obj1, obj2 ),此时,target为arguments[0]
        i = 1,
        length = arguments.length,
        deep = false;

    // Handle a deep copy situation
    if ( typeof target === "boolean" ) {    // 如果第一个参数为true,即 jQuery.extend( true, obj1, obj2 ); 的情况
        deep = target;  // 此时target是true
        target = arguments[1] || {};    // target改为 obj1
        // 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) ) {  // 处理奇怪的情况,比如 jQuery.extend( 'hello' , {nick: 'casper})~~
        target = {};
    }

    // extend jQuery itself if only one argument is passed
    if ( length === i ) {   // 处理这种情况 jQuery.extend(obj),或 jQuery.fn.extend( obj )
        target = this;  // jQuery.extend时,this指的是jQuery;jQuery.fn.extend时,this指的是jQuery.fn
        --i;
    }

    for ( ; i < length; i++ ) {
        // Only deal with non-null/undefined values
        if ( (options = arguments[ i ]) != null ) { // 比如 jQuery.extend( obj1, obj2, obj3, ojb4 ),options则为 obj2、obj3...
            // 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 {    被拷贝的属性值是个plainObject,比如{ nick: 'casper' }
                        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 ) {  // 浅拷贝,且属性值不为undefined
                    target[ name ] = copy;
                }
            }
        }
    }

    // Return the modified object
    return target;
}

extent函数源码分析引用自:http://www.cnblogs.com/aaronjs/p/3278578.html

实现自己的简单深复制函数

深复制需要遵守的规则:(假设将obj2中的属性深复制至obj1中)

  1. obj2中的某个属性bar为对象或者数组。如果obj1.bar为也为数组或对象,将obj1.bar与obj2.bar作为参数再次执行深复制;如果obj1.bar不为数组、对象或者obj.bar不存在,则新建一个数组、对象,与obj2.bar作为参数再次执行深复制。
  2. obj2中的某个属性foo不为数组或者对象,直接令obj1.foo = obj2.foo。

实现:(https://github.com/kangkang1234/deepCopy/blob/master/deepCopy.js

function deepCopy(){
    var len = arguments.length;
    if(len===1){
        return arguments[0];
    }else if(len===0){
        return undefined;
    }
    var j=0;
    for(;j<len;j++){
        if(!(arguments[j] instanceof Array)&&!(arguments[j] instanceof Object)){
            throw new TypeError("arguments must be object or array.");
        }
    }
    var src,copy,option,copyIsArr;
    var target = arguments[0] || {};
    var i = 1;
    for(;i<len;i++){
        option = arguments[i];
        for(name in option){
            src = target[name];
            copy = option[name];
            if(copy&&((copyIsArr=copy instanceof Array)||(copy instanceof Object))){  //如果copy存在并且是数组或者对象
                if(copyIsArr){   //如果copy是数组
                    src = (src&&src instanceof Array)?src:[];  //判断target中是否有相同属性名的属性,并且该属性为数组。
                    target[name] = deepCopy(src,copy);
                }else{
                    src = src?src:{};
                    target[name] = deepCopy(src,copy);
                }
            }
            else {
                target[name] = copy;
            }
        }
    }
    return target;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值