成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

深復(fù)制、淺復(fù)制與JQuery中的插件開(kāi)發(fā)

sewerganger / 3347人閱讀

摘要:變量表示深度復(fù)制時(shí)原始值的修正值。中的復(fù)制方法復(fù)制的方法分別是和。此處不能正確處理的深復(fù)制綜合三種方法來(lái)看不能復(fù)制對(duì)象以外的對(duì)象。

學(xué)習(xí)前端半年多了,還停留在新手村級(jí),寫的文章可能有很多問(wèn)題,思維方式和邏輯上還不夠嚴(yán)密,希望能指出問(wèn)題,謝謝!

=====================================================================

數(shù)據(jù)類型

數(shù)據(jù)類型分為兩種,基本數(shù)據(jù)類型和引用數(shù)據(jù)類型。ES6中的數(shù)據(jù)類型不做討論,基本類型包括了:string、null、undefined、number、boolean。引用類型:object。它是由一個(gè)或者多個(gè)鍵名鍵值對(duì)的對(duì)象。基本數(shù)據(jù)類型保存在棧內(nèi)存中,而引用類型保存在堆內(nèi)存中,棧內(nèi)存中的數(shù)據(jù)必須是固定大小的,而引用類型的大小不固定,所以只能白存在堆內(nèi)存中,將堆內(nèi)存中的地址直接賦值出來(lái)之后就可以訪問(wèn)引用類型數(shù)據(jù)。他們之間的差別如下:

區(qū)別 基本數(shù)據(jù)類型 引用數(shù)據(jù)類型
保存位置 棧內(nèi)存 堆內(nèi)存
數(shù)據(jù)大小 固定大小 不固定
訪問(wèn)方式 通過(guò)變量保存的值 通過(guò)保存的地址訪問(wèn)
淺復(fù)制與深復(fù)制

在淺復(fù)制時(shí)直接將簡(jiǎn)單類型值分別賦值給target,而如果復(fù)制的是對(duì)象就不能通過(guò)簡(jiǎn)單的復(fù)值來(lái)復(fù)制。這樣做成的結(jié)果就是target引用值改變時(shí)也會(huì)引起原對(duì)象的改變。

1.淺復(fù)制
    var person1 = ["Nicholas","Greg",[{
                        name : "linda",
                        age : 21                    
                    },{
                        name : "Nancy",
                        age : 19
                    }]
                ]; 
    var person2 = [];
    // //復(fù)制
    for(var i  = 0;i < person1.length;i++){
        person2[i] = person1[i]; 
    }
    person2[2].push("Leo") ;//改變color1的值
    console.log(person2);//"Nicholas","Greg",Array(3)
    console.log(person1);//"Nicholas","Greg",Array(3)

只復(fù)制第一層屬性的方式為淺復(fù)制,如果數(shù)據(jù)類型全部是基本類型是可以成功的,而在復(fù)制引用類型時(shí),則需要復(fù)制到基本類型為止才可以保證互不影響。

2.深復(fù)制

原生方法的基本實(shí)現(xiàn)方式:

    var objA = {
        a : "fc",
        b : "Ig",
        c : {
            d(){
                console.log(1)
            }
        }
    }
    function deepCopy(sub,sup){
        for(var key in sup){
            if(typeof sup[key] === "object"){
                sub[key] = {};
                //復(fù)制到對(duì)象上的屬性值為基本類型值為止
                deepCopy(sub[key],sup[key]);
            }else{
                sub[key] = sup[key];
            } 
        }
        return sub;
    }
    var objB = {};
    deepCopy(objB,objA);

    objA.c.d = function(){
        console.log(2)
    }
    //修改源對(duì)象上的屬性并不會(huì)修改目標(biāo)對(duì)象上已經(jīng)復(fù)制的屬性
    objB.c.d();//1

深復(fù)制的原理就是如果復(fù)制時(shí)如果復(fù)制的對(duì)象時(shí)引用類型,那么就遞歸運(yùn)行復(fù)制一次,直到為簡(jiǎn)單數(shù)據(jù)類型為止。

$.extend方法

在JQuery的extend方法中,如果傳入的是一個(gè)或多個(gè)對(duì)象,那么就會(huì)將后面對(duì)象的屬性復(fù)制給target對(duì)象,第一個(gè)參數(shù)可以選擇是深復(fù)制(true)或淺復(fù)制,默認(rèn)為淺復(fù)制,返回的是被擴(kuò)展的對(duì)象。

1.合并但不修改object1。$.extend({}, object1, object2);

    var settings = {first:"hello", second: "world"};
    var options = {first:"hello", second: "JavaScript",third: "nodeJs"};
    var results = $.extend({}, settings, options);

2.合并并修改第一個(gè)對(duì)象。$.extend(obj1,obj2)

    var obj1 = {first: 1, second: {height: 178, weight: 70,length:100}};
    var obj2 = {second: {height:180, weight:65, width: 90}, third: 90};
    $.extend(obj1, obj2);
    
    //輸出結(jié)果為:{first: 1, second: {height:180,weight:65, width: 90}, third: 90}

3.深復(fù)制對(duì)象。$.extend(true,obj1,obj2)

    var obj1 = {first: 1, second: {height: 178, weight: 70}};
    var obj2 = {second: {height:180, weight: 65, width: 90}, third: 90};
    $.extend(true,obj1,obj2);
    console.log(obj1,obj2);
    //輸出結(jié)果為:{first: 1, second: Object, third: 90}
深復(fù)制的不同種實(shí)現(xiàn)方式

已知的三種方式,$.extend、lodash、Underscore都有可以實(shí)現(xiàn)復(fù)制的功能,但是也會(huì)有一些細(xì)微的區(qū)別。

1.在Underscore中的_.clone(),如下:

    var x = {
        a: 1,
        b: { z: 0 },
        c:[
            2,3,9
        ]
    };

    var y = _.clone(x);
    y.c.push(29);
    console.log(x.c,y.c);//[2, 3, 9, 29][2, 3, 9, 29];
    //_.clone源碼部分
    _.clone = function(obj) {
      if (!_.isObject(obj)) return obj;
      return _.isArray(obj) ? obj.slice() : _.extend({}, obj);
    };
    //數(shù)組使用slice方法截取所有,對(duì)象采用淺復(fù)制上的方法復(fù)制對(duì)象后按鍵值賦值,由此可見(jiàn)該功能并不能實(shí)現(xiàn)深復(fù)制

2.$.extend的復(fù)制方法
該方法下的深復(fù)制原理是:通過(guò)添加參數(shù)來(lái)實(shí)現(xiàn)遞歸extend,因此JQuery可以實(shí)現(xiàn)深復(fù)制。源碼(3.2版本)如下:

    jQuery.extend = jQuery.fn.extend = function(){
        var options, name, src, copy, copyIsArray, clone,
            target = arguments[ 0 ] || {},// 常見(jiàn)用法 jQuery.extend( obj1, obj2 ),此時(shí),target為arguments[0]
            i = 1,
            length = arguments.length,
            deep = false;
            /*
            變量 options:指向某個(gè)源對(duì)象。
            變量 name:表示某個(gè)源對(duì)象的某個(gè)屬性名。
            變量 src:表示目標(biāo)對(duì)象的某個(gè)屬性的原始值。
            變量 copy:表示某個(gè)源對(duì)象的某個(gè)屬性的值。
            變量 copyIsArray:指示變量 copy 是否是數(shù)組。
            變量 clone:表示深度復(fù)制時(shí)原始值的修正值。
            變量 target:指向目標(biāo)對(duì)象,申明時(shí)先臨時(shí)用第一個(gè)參數(shù)值。
            變量 i:表示源對(duì)象的起始下標(biāo),申明時(shí)先臨時(shí)用第二個(gè)參數(shù)值。
            變量 length:表示參數(shù)的個(gè)數(shù),用于修正變量 target。
            變量 deep:指示是否執(zhí)行深度復(fù)制,默認(rèn)為 false。
            */
            
        if( typeof target === "boolean" ){
        //如果第一個(gè)參數(shù)為true,即 jQuery.extend( true, obj1, obj2 ); 的情況
            deep = target;
            target = arguments[ i ] || {};
            i++;
        }
        
        //Handle case when target is a string or something (possible in deep copy)
        //比如$.extend({},{adress:"LosAngles"})
        if( typeof target !== "object" && !jQuery.isFunction( target ) ){
            target = {};
        }
        // Extend jQuery itself if only one argument is passed
        // 處理這種情況 jQuery.extend(obj),或jQuery.fn.extend(obj)
        if( i === length ){
            target = this;
            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...
                for( name in options ) {
                    src = target[ name ];
                    copy = options[ name ];
    
                    // 防止自引用
                    if( target === copy ) {
                        continue;
                    }
                    // 如果是深拷貝,且被拷貝的屬性值本身是個(gè)對(duì)象或數(shù)組
                    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 : {};
                        }
                        // Never move original objects, clone them
                        target[ name ] = jQuery.extend( deep, clone, copy );
                    //普通對(duì)象的定義是:通過(guò) "{}"或者"new Object" 創(chuàng)建的    
                    //之前的例子走到了這一步,直接的賦值給對(duì)象,所以改變了源對(duì)象的屬性后,target對(duì)象的屬性也會(huì)發(fā)生改變
                    }else if( copy !== undefined ){
                        target[ name ] = copy;
                    }
                }
            }
        }
        return target;
    };

根據(jù)extend的源碼分析,在關(guān)于深復(fù)制這部分的核心代碼中,判斷源對(duì)象的屬性上是不是"普通對(duì)象"這個(gè)問(wèn)題可能會(huì)引起深復(fù)制結(jié)果的錯(cuò)誤。

例如在以下的代碼中就可以看出,因?yàn)榕袛鄌bj不是"普通對(duì)象",所以會(huì)影響深復(fù)制的結(jié)果,在這個(gè)例子中,當(dāng)改變了源對(duì)象的屬性時(shí),目標(biāo)對(duì)象的屬性也被改變,顯然這不符合深復(fù)制的目的。同樣的問(wèn)題在下面的lodash深復(fù)制中并不會(huì)出現(xiàn)。

    function Obj(){
        this.a = 1;
    }
    var obj = new Obj();
    var tobeCloned = {o:obj};
    var result  = $.extend(true,{},tobeCloned);
    tobeCloned.o.a = 2;
    console.log(result.o.a)//2
    
    console.log($.isPlainObject(obj));//false

3.lodash中的復(fù)制方法
復(fù)制的方法分別是_.clone()和_.cloneDeep()。其中_.clone(obj, true)等價(jià)于_.cloneDeep(obj)。

    var arr = new Int16Array(5),
    obj = { a: arr },
    obj2;
    arr[0] = 5;
    arr[1] = 6;
    
    //Int16Array是類型化數(shù)組。16位二補(bǔ)碼有符號(hào)整數(shù)。
    // 1. jQuery
    obj2 = $.extend(true,{},obj);
    console.log(obj2.a);                            // [5, 6, 0, 0, 0]
    Object.prototype.toString.call(obj2);           // [object Int16Array]
    obj2.a[0] = 100;
    console.log(obj);                               // [100, 6, 0, 0, 0]
    
    //此處jQuery不能正確處理Int16Array的深復(fù)制!?。?    // 2. lodash
    obj2 = _.cloneDeep(obj);                       
    console.log(obj2.a);                            // [5, 6, 0, 0, 0]
    Object.prototype.toString.call(arr2);           // [object Int16Array]
    obj2.a[0] = 100;
    console.log(obj);                               // [5, 6, 0, 0, 0]

綜合三種方法來(lái)看,JQuery不能復(fù)制JSON對(duì)象以外的對(duì)象。而在lodash中用了大量的代碼來(lái)實(shí)現(xiàn)ES6引入的新標(biāo)準(zhǔn)對(duì)象,并且還可以對(duì)Date、RegExp進(jìn)行深復(fù)制。單就深復(fù)制的實(shí)現(xiàn)上來(lái)說(shuō),lodash的效率和適用范圍要優(yōu)于JQuery。因此可以說(shuō)lodash是一種更擁抱未來(lái)的類庫(kù)。

JQuery插件

JQuery插件主要分為兩類:1,類級(jí)別 2,對(duì)象級(jí)別

類方法。直接使用$類引用,不需要實(shí)例化就可使用。類方法在項(xiàng)目中被設(shè)置為工具類使用。

對(duì)象級(jí)別。必須先創(chuàng)建實(shí)例,然后才能通過(guò)實(shí)例調(diào)用該實(shí)例方法。

1.$.extend擴(kuò)展

直接擴(kuò)展JQuery類,相當(dāng)于靜態(tài)方法,典型的方法有$.ajax,擴(kuò)展方法:

    $.extend({
        add:function(a,b){
            return a + b;
        },
        divide:function(a,b){
            return a/b;
        }
    })
    //調(diào)用方式
    $.add(3,0);
    $.divide(9,3);
2.$.fn.extend()擴(kuò)展插件

這種擴(kuò)展方式是基于原型對(duì)象的,擴(kuò)展插件時(shí)一般使用這種方式,擴(kuò)展之后只有JQuery的實(shí)例才可以調(diào)用該方法,比如希望使頁(yè)面上所有的連接轉(zhuǎn)為紅色。

    $.fn.myLink = function(){
        this.css({
            "color":"red"
        })
    }
    $("a").myLink();

如果需要對(duì)每個(gè)具體的元素進(jìn)行操作,可以對(duì)該方法再次進(jìn)行擴(kuò)展。

    $.fn.myLink = function(){
        this.css({
            "color":"red"
        });
        this.each(function(){
            $(this).append($(this).attr("href"));
        })
    }
    $("a").myLink();

注意在each的內(nèi)部遍歷出來(lái)的是DOM元素,所以需要在包裝一次才可以使用JQuery的方法。而如果我們希望可以自己定制,根據(jù)自身需求來(lái)設(shè)置,所以可以利用$.extend方法合并對(duì)象之后來(lái)作為參數(shù)使用,在沒(méi)有參數(shù)時(shí)使用默認(rèn)值。
在extend時(shí)使用空對(duì)象作為第一個(gè)參數(shù),避免修改defaults默認(rèn)的屬性值,保護(hù)好defaults的默認(rèn)參數(shù)。

    $.fn.myLink = function(options){
        var defaults = {
            "color" : "red",
            "fontSize" : "18px",
            "lineHeight" : "18px"
        }
        //此處使用空對(duì)象是為了保護(hù)默認(rèn)參數(shù),避免被修改之后復(fù)用出錯(cuò),注意默認(rèn)還是淺復(fù)制,如果options有引用類型參數(shù)時(shí),還是會(huì)對(duì)defaults造成印象
        var setting = $.extend({},defaults,options);
        return this.css({
            "color" : setting.color,
            "fontSize" : setting.fontSize,
            "lineHeight" : setting.lineHeight
        })
    }
    $("a").myLink({
        "color":"#333"
    });
3.面向?qū)ο蟮牟寮_(kāi)發(fā)

為什么需要面向?qū)ο蟮牟寮椒??方便管理直接使用,第二不?huì)影響外部命名空間。

    ;(function($,window,document,undefined){
        var Beautify = function(ele,opt){
            this.$elements = ele,
            this.defaults = {
                "color" : "red",
                "fontSize" : "18px",
                "textShadow" : "none"
            },
            this.options = $.extend({},this.defaults,opt);
        }
        Beautify.prototype = {
            constructor : Beautify,
            beautiful(){
                return this.$elements.css({
                    "color" : this.options.color,
                    "fontSize" : this.options.fontSize,
                    "textShadow" : this.options.textShadow
                })
            }
        }
        $.fn.myPlug = function(options){
            //this指向新的實(shí)例beautify,其中有一個(gè)函數(shù)beautify(),可以返回指定樣式;
            var beautify = new Beautify(this,options);
            return beautify.beautiful();
        }
    })(jQuery,window,document,undefined);
    $("").myPlug({
        "fontSize":"30px",
        "textShadow": "3px 2px 3px #ff0000"
    })

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/82654.html

相關(guān)文章

  • 解析js對(duì)象的復(fù)制復(fù)制原理

    摘要:淺復(fù)制假設(shè)有兩個(gè)對(duì)象現(xiàn)在想把對(duì)象的值復(fù)制給,由于對(duì)象的兩個(gè)值都是原始類型,用淺復(fù)制即可。深復(fù)制簡(jiǎn)單來(lái)說(shuō)深復(fù)制就是當(dāng)遇到值是對(duì)象類型的時(shí)候就再運(yùn)行一遍復(fù)制。 試想這樣一種場(chǎng)景,自己編寫了一個(gè)js插件,調(diào)用插件時(shí)參數(shù)是以對(duì)象的形式傳入的,插件也有自己的默認(rèn)值,當(dāng)運(yùn)行的時(shí)候就涉及到傳入?yún)?shù)和默認(rèn)值的合并,即用到對(duì)象的深復(fù)制和淺復(fù)制。 淺復(fù)制 假設(shè)有兩個(gè)對(duì)象 var objA = { a:...

    wenyiweb 評(píng)論0 收藏0
  • 20170606-拷貝拷貝

    摘要:什么是深拷貝,什么是淺拷貝中的淺拷貝與深拷貝是針對(duì)復(fù)雜數(shù)據(jù)類型引用類型的復(fù)制問(wèn)題。 什么是深拷貝,什么是淺拷貝 JS中的淺拷貝與深拷貝是針對(duì)復(fù)雜數(shù)據(jù)類型(引用類型)的復(fù)制問(wèn)題。 淺拷貝:淺拷貝是拷貝引用(拷貝地址),拷貝后兩個(gè)變量指向的是同一塊內(nèi)存空間 深拷貝:會(huì)在內(nèi)存中開(kāi)辟一塊新的內(nèi)存空間,它不僅將原對(duì)象的各個(gè)屬性逐個(gè)復(fù)制過(guò)去,而且將原對(duì)象各個(gè)屬性所包含的內(nèi)容也依次采用深復(fù)制的方法...

    Kerr1Gan 評(píng)論0 收藏0
  • Javascript對(duì)象的拷貝

    摘要:開(kāi)門見(jiàn)山,有人叫對(duì)象的復(fù)制為深復(fù)制淺復(fù)制,也有人叫深拷貝淺拷貝。高級(jí)屬性修改深拷貝滿足對(duì)象的復(fù)制,淺拷貝影響原數(shù)組。關(guān)于對(duì)象的深淺拷貝,暫且探索到這里,后續(xù)有新發(fā)現(xiàn)再進(jìn)行補(bǔ)充。 showImg(https://segmentfault.com/img/remote/1460000014305581); 開(kāi)門見(jiàn)山,有人叫對(duì)象的復(fù)制為深復(fù)制淺復(fù)制,也有人叫深拷貝淺拷貝。其實(shí)都是copy。 ...

    qieangel2013 評(píng)論0 收藏0
  • jQuery源碼學(xué)習(xí)之extend

    摘要:源碼學(xué)習(xí)之用于合并對(duì)象,可選擇是否深復(fù)制。盡管官方文檔明確指出第一個(gè)參數(shù)是的調(diào)用情況并不支持,但是這個(gè)版本的源碼中,判斷第一個(gè)參數(shù)的類型雖有限定是類型,但卻未對(duì)其值真假加以限定。調(diào)用方式源碼和指向同一個(gè)函數(shù),在函數(shù)內(nèi)部,對(duì)調(diào)用情況進(jìn)行區(qū)分。 jQuery源碼學(xué)習(xí)之extend $.extend用于合并對(duì)象,可選擇是否深復(fù)制。使用時(shí),第一個(gè)參數(shù)為合并后的對(duì)象。如果要進(jìn)行深拷貝,則參數(shù)1為...

    quietin 評(píng)論0 收藏0
  • JS每日一題:拷貝拷貝的區(qū)別?如何實(shí)現(xiàn)一個(gè)拷貝

    摘要:期深拷貝與淺拷貝的區(qū)別如何實(shí)現(xiàn)一個(gè)深拷貝在回答這個(gè)問(wèn)題前,我們先來(lái)回顧一下中兩大數(shù)據(jù)類型基本類型引用類型基本類型基本類型就是值類型存放在棧內(nèi)存中的簡(jiǎn)單數(shù)據(jù)段,數(shù)據(jù)大小確定,內(nèi)存空間大小可以分配引用類型引用類型存放在堆內(nèi)存中的對(duì)象,變量實(shí)際保 20190311期 深拷貝與淺拷貝的區(qū)別?如何實(shí)現(xiàn)一個(gè)深拷貝 在回答這個(gè)問(wèn)題前,我們先來(lái)回顧一下JS中兩大數(shù)據(jù)類型 基本類型 Undefined...

    MiracleWong 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<