摘要:變量表示深度復制時原始值的修正值。中的復制方法復制的方法分別是和。此處不能正確處理的深復制綜合三種方法來看不能復制對象以外的對象。
學習前端半年多了,還停留在新手村級,寫的文章可能有很多問題,思維方式和邏輯上還不夠嚴密,希望能指出問題,謝謝!
=====================================================================
數據類型數據類型分為兩種,基本數據類型和引用數據類型。ES6中的數據類型不做討論,基本類型包括了:string、null、undefined、number、boolean。引用類型:object。它是由一個或者多個鍵名鍵值對的對象?;緮祿愋捅4嬖跅却嬷?而引用類型保存在堆內存中,棧內存中的數據必須是固定大小的,而引用類型的大小不固定,所以只能白存在堆內存中,將堆內存中的地址直接賦值出來之后就可以訪問引用類型數據。他們之間的差別如下:
區別 | 基本數據類型 | 引用數據類型 |
---|---|---|
保存位置 | 棧內存 | 堆內存 |
數據大小 | 固定大小 | 不固定 |
訪問方式 | 通過變量保存的值 | 通過保存的地址訪問 |
在淺復制時直接將簡單類型值分別賦值給target,而如果復制的是對象就不能通過簡單的復值來復制。這樣做成的結果就是target引用值改變時也會引起原對象的改變。
1.淺復制var person1 = ["Nicholas","Greg",[{ name : "linda", age : 21 },{ name : "Nancy", age : 19 }] ]; var person2 = []; // //復制 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)
只復制第一層屬性的方式為淺復制,如果數據類型全部是基本類型是可以成功的,而在復制引用類型時,則需要復制到基本類型為止才可以保證互不影響。
2.深復制原生方法的基本實現方式:
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] = {}; //復制到對象上的屬性值為基本類型值為止 deepCopy(sub[key],sup[key]); }else{ sub[key] = sup[key]; } } return sub; } var objB = {}; deepCopy(objB,objA); objA.c.d = function(){ console.log(2) } //修改源對象上的屬性并不會修改目標對象上已經復制的屬性 objB.c.d();//1
深復制的原理就是如果復制時如果復制的對象時引用類型,那么就遞歸運行復制一次,直到為簡單數據類型為止。
$.extend方法在JQuery的extend方法中,如果傳入的是一個或多個對象,那么就會將后面對象的屬性復制給target對象,第一個參數可以選擇是深復制(true)或淺復制,默認為淺復制,返回的是被擴展的對象。
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.合并并修改第一個對象。$.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); //輸出結果為:{first: 1, second: {height:180,weight:65, width: 90}, third: 90}
3.深復制對象。$.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); //輸出結果為:{first: 1, second: Object, third: 90}深復制的不同種實現方式
已知的三種方式,$.extend、lodash、Underscore都有可以實現復制的功能,但是也會有一些細微的區別。
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); }; //數組使用slice方法截取所有,對象采用淺復制上的方法復制對象后按鍵值賦值,由此可見該功能并不能實現深復制
2.$.extend的復制方法
該方法下的深復制原理是:通過添加參數來實現遞歸extend,因此JQuery可以實現深復制。源碼(3.2版本)如下:
jQuery.extend = jQuery.fn.extend = function(){ var options, name, src, copy, copyIsArray, clone, target = arguments[ 0 ] || {},// 常見用法 jQuery.extend( obj1, obj2 ),此時,target為arguments[0] i = 1, length = arguments.length, deep = false; /* 變量 options:指向某個源對象。 變量 name:表示某個源對象的某個屬性名。 變量 src:表示目標對象的某個屬性的原始值。 變量 copy:表示某個源對象的某個屬性的值。 變量 copyIsArray:指示變量 copy 是否是數組。 變量 clone:表示深度復制時原始值的修正值。 變量 target:指向目標對象,申明時先臨時用第一個參數值。 變量 i:表示源對象的起始下標,申明時先臨時用第二個參數值。 變量 length:表示參數的個數,用于修正變量 target。 變量 deep:指示是否執行深度復制,默認為 false。 */ if( typeof target === "boolean" ){ //如果第一個參數為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; } // 如果是深拷貝,且被拷貝的屬性值本身是個對象或數組 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 ); //普通對象的定義是:通過 "{}"或者"new Object" 創建的 //之前的例子走到了這一步,直接的賦值給對象,所以改變了源對象的屬性后,target對象的屬性也會發生改變 }else if( copy !== undefined ){ target[ name ] = copy; } } } } return target; };
根據extend的源碼分析,在關于深復制這部分的核心代碼中,判斷源對象的屬性上是不是"普通對象"這個問題可能會引起深復制結果的錯誤。
例如在以下的代碼中就可以看出,因為判斷obj不是"普通對象",所以會影響深復制的結果,在這個例子中,當改變了源對象的屬性時,目標對象的屬性也被改變,顯然這不符合深復制的目的。同樣的問題在下面的lodash深復制中并不會出現。
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中的復制方法
復制的方法分別是_.clone()和_.cloneDeep()。其中_.clone(obj, true)等價于_.cloneDeep(obj)。
var arr = new Int16Array(5), obj = { a: arr }, obj2; arr[0] = 5; arr[1] = 6; //Int16Array是類型化數組。16位二補碼有符號整數。 // 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的深復制?。。? // 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]
綜合三種方法來看,JQuery不能復制JSON對象以外的對象。而在lodash中用了大量的代碼來實現ES6引入的新標準對象,并且還可以對Date、RegExp進行深復制。單就深復制的實現上來說,lodash的效率和適用范圍要優于JQuery。因此可以說lodash是一種更擁抱未來的類庫。
JQuery插件JQuery插件主要分為兩類:1,類級別 2,對象級別
類方法。直接使用$類引用,不需要實例化就可使用。類方法在項目中被設置為工具類使用。
對象級別。必須先創建實例,然后才能通過實例調用該實例方法。
1.$.extend擴展直接擴展JQuery類,相當于靜態方法,典型的方法有$.ajax,擴展方法:
$.extend({ add:function(a,b){ return a + b; }, divide:function(a,b){ return a/b; } }) //調用方式 $.add(3,0); $.divide(9,3);2.$.fn.extend()擴展插件
這種擴展方式是基于原型對象的,擴展插件時一般使用這種方式,擴展之后只有JQuery的實例才可以調用該方法,比如希望使頁面上所有的連接轉為紅色。
$.fn.myLink = function(){ this.css({ "color":"red" }) } $("a").myLink();
如果需要對每個具體的元素進行操作,可以對該方法再次進行擴展。
$.fn.myLink = function(){ this.css({ "color":"red" }); this.each(function(){ $(this).append($(this).attr("href")); }) } $("a").myLink();
注意在each的內部遍歷出來的是DOM元素,所以需要在包裝一次才可以使用JQuery的方法。而如果我們希望可以自己定制,根據自身需求來設置,所以可以利用$.extend方法合并對象之后來作為參數使用,在沒有參數時使用默認值。
在extend時使用空對象作為第一個參數,避免修改defaults默認的屬性值,保護好defaults的默認參數。
$.fn.myLink = function(options){ var defaults = { "color" : "red", "fontSize" : "18px", "lineHeight" : "18px" } //此處使用空對象是為了保護默認參數,避免被修改之后復用出錯,注意默認還是淺復制,如果options有引用類型參數時,還是會對defaults造成印象 var setting = $.extend({},defaults,options); return this.css({ "color" : setting.color, "fontSize" : setting.fontSize, "lineHeight" : setting.lineHeight }) } $("a").myLink({ "color":"#333" });3.面向對象的插件開發
為什么需要面向對象的插件方法?方便管理直接使用,第二不會影響外部命名空間。
;(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指向新的實例beautify,其中有一個函數beautify(),可以返回指定樣式; var beautify = new Beautify(this,options); return beautify.beautiful(); } })(jQuery,window,document,undefined); $("").myPlug({ "fontSize":"30px", "textShadow": "3px 2px 3px #ff0000" })
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/82654.html
摘要:淺復制假設有兩個對象現在想把對象的值復制給,由于對象的兩個值都是原始類型,用淺復制即可。深復制簡單來說深復制就是當遇到值是對象類型的時候就再運行一遍復制。 試想這樣一種場景,自己編寫了一個js插件,調用插件時參數是以對象的形式傳入的,插件也有自己的默認值,當運行的時候就涉及到傳入參數和默認值的合并,即用到對象的深復制和淺復制。 淺復制 假設有兩個對象 var objA = { a:...
摘要:什么是深拷貝,什么是淺拷貝中的淺拷貝與深拷貝是針對復雜數據類型引用類型的復制問題。 什么是深拷貝,什么是淺拷貝 JS中的淺拷貝與深拷貝是針對復雜數據類型(引用類型)的復制問題。 淺拷貝:淺拷貝是拷貝引用(拷貝地址),拷貝后兩個變量指向的是同一塊內存空間 深拷貝:會在內存中開辟一塊新的內存空間,它不僅將原對象的各個屬性逐個復制過去,而且將原對象各個屬性所包含的內容也依次采用深復制的方法...
摘要:開門見山,有人叫對象的復制為深復制淺復制,也有人叫深拷貝淺拷貝。高級屬性修改深拷貝滿足對象的復制,淺拷貝影響原數組。關于對象的深淺拷貝,暫且探索到這里,后續有新發現再進行補充。 showImg(https://segmentfault.com/img/remote/1460000014305581); 開門見山,有人叫對象的復制為深復制淺復制,也有人叫深拷貝淺拷貝。其實都是copy。 ...
摘要:源碼學習之用于合并對象,可選擇是否深復制。盡管官方文檔明確指出第一個參數是的調用情況并不支持,但是這個版本的源碼中,判斷第一個參數的類型雖有限定是類型,但卻未對其值真假加以限定。調用方式源碼和指向同一個函數,在函數內部,對調用情況進行區分。 jQuery源碼學習之extend $.extend用于合并對象,可選擇是否深復制。使用時,第一個參數為合并后的對象。如果要進行深拷貝,則參數1為...
摘要:期深拷貝與淺拷貝的區別如何實現一個深拷貝在回答這個問題前,我們先來回顧一下中兩大數據類型基本類型引用類型基本類型基本類型就是值類型存放在棧內存中的簡單數據段,數據大小確定,內存空間大小可以分配引用類型引用類型存放在堆內存中的對象,變量實際保 20190311期 深拷貝與淺拷貝的區別?如何實現一個深拷貝 在回答這個問題前,我們先來回顧一下JS中兩大數據類型 基本類型 Undefined...
閱讀 489·2021-09-03 00:22
閱讀 1365·2021-08-03 14:03
閱讀 2082·2021-07-25 21:37
閱讀 646·2019-08-30 13:18
閱讀 1875·2019-08-29 16:19
閱讀 2682·2019-08-29 13:22
閱讀 1293·2019-08-29 12:16
閱讀 2587·2019-08-26 12:16