jquery源碼學習(一):本身實現一個簡單的深複製函數

jquery源碼分析

jquery$(selector).bar()調用方法的實現

$(selector)須要返回一個利用selector初始化的實例,而且這個實例可以訪問jquery的原型方法,而且不使用new操做符。html

實現這兩步,須要:jquery

  1. 構造函數$須要返回一個用new操做符調用的構造函數init的實例
  2. 將構造函數init的prototype屬性設置爲jQuery的prototype屬性

咱們能夠這樣作:git

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

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

function init(){
    ...;
}

*init.prototype = $.prototype

var something = $(selector);

可是在jquery中,init函數是在$.prototype內部的,所以帶星號的語句須要修改成:github

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函數源碼分析oop

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則爲 obj二、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中)this

  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.jsspa

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;
}
相關文章
相關標籤/搜索