摘要:變量表示深度復(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ù)制時(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
摘要:淺復(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:...
摘要:什么是深拷貝,什么是淺拷貝中的淺拷貝與深拷貝是針對(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ù)制的方法...
摘要:開(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。 ...
摘要:源碼學(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為...
摘要:期深拷貝與淺拷貝的區(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...
閱讀 509·2021-09-03 00:22
閱讀 1382·2021-08-03 14:03
閱讀 2102·2021-07-25 21:37
閱讀 661·2019-08-30 13:18
閱讀 1889·2019-08-29 16:19
閱讀 2697·2019-08-29 13:22
閱讀 1320·2019-08-29 12:16
閱讀 2597·2019-08-26 12:16