javascript
js动态创建对象_JS深浅拷贝的深入浅出
一 首先了解JavaScript中的基本數(shù)據(jù)類型
? ? ?基本數(shù)據(jù)類型:String,Number,Boolean,Null,Undefined
? ? ?引用數(shù)據(jù)類型:Araay,Date,RegExp,Function
二 基本數(shù)據(jù)類型和引用數(shù)據(jù)類型的區(qū)別?
? ? ?(1)它們保存的位置不同:基本數(shù)據(jù)保存在棧中,引用數(shù)據(jù)類型保存在堆內存中。JS對引用數(shù)據(jù)的操作其實操作對象的引用而不是實際的對象,也就是指向實際對象的內存地址,如果obj1拷貝了obj2,那么這兩個對象指向了同一堆內存對象,具體就是吧obj1棧內存中的引用地址復制了一份給obj2,所以他們指向了同一個堆內存對象。
? ? ? ??那為什么基本數(shù)據(jù)類型要存在棧內存中,而引用數(shù)據(jù)要存在堆內存中?
??? ? ? ?(1)堆比棧大,棧的查找速度比堆塊。
?? ? ? ? (2)基本數(shù)據(jù)類型比較的穩(wěn)定,相對的話占用的內存比較小
? ? ? ? ?(3)引用數(shù)據(jù)類型一般都是動態(tài)的,而且可能是無限大,引用的值也經(jīng)常改變,所以不能放在棧中,這樣會降低查找的速度,因此放在變量棧中的值應該是指向該對象再堆內存中的地址,地址的大小的固定的,所以吧他存在棧中對變量的性能沒有影響。
? ? ? JS一般在訪問存在堆內存的對象的時候是不能直接訪問的,所以在訪問對象的時候,要先獲取改對象再堆內存中的地址,在根據(jù)改地址去訪問該對象中的值。
? ??(2)基本數(shù)據(jù)類型可以使用typeof可以返回基本數(shù)據(jù)類型,但是Null會返回object,所以Null表示一個空對象指針;引用數(shù)據(jù)類型使用typeof會返回object,所以引用數(shù)據(jù)類型要用instanceof來檢測引用數(shù)據(jù)的類型。
? ? (3)定義引用數(shù)據(jù)類型需要使用new操作符,后面在跟一個構造函數(shù)來創(chuàng)建,或者使用對象字面量表示法創(chuàng)建對象。
? ? ? ? 使用new操作符創(chuàng)建對象
var obj1 = new Object();obj1.a = 1;? ? ? ? 使用對象字面量表示法創(chuàng)建對象
var obj1 = { a: 1, b: 2}基本數(shù)據(jù)類型 name和value值都是存儲在棧中
當b=a的時候
棧內存開辟了一個新內存出來,所以在修改a的值的時候不會影響到b的值
引用數(shù)據(jù)類型-name是存在棧中,value存在堆內存中,但是棧內存會提供一個引用地址指向該對象在堆內存中的值
當b=a拷貝時,其實復制的是a的引用地址,并不是堆內存中的值
當你修改a里面的值的時候,由于a與b指向的是同一個地址所以b也就受到了影響,這就是淺拷貝。
如果在堆內存中開辟了一個新的內存地址專門存在b的值的話,那就達到了深拷貝的效果了。
三 什么是深拷貝和淺拷貝
? ? ? 首先深拷貝和淺拷貝都只針對于引用類型的數(shù)據(jù);淺拷貝只復制指向某個對象的指針,并不復制對象的本身,新原對象還是共享同一塊內存,但是深拷貝會創(chuàng)造一個一模一樣的新對象出來,新對象跟原對象不再共享同一塊內存地址,修改新對象也不會影響到原對象。
? ? ? ?區(qū)別:淺拷貝只復制對象的第一層屬性,深拷貝可以對對象的屬性進行遞歸復制。
四 實現(xiàn)深拷貝
? ?1、json對象的parse和stringfy
function deepClone (obj) { let _obj = JSON.stringify(obj) let objClone = JSON.parse(_obj) return objClone} let a = [0,1,2,3,4]let b = deepClone(a) a[0] = 1 console.log(a) //[1,1,2,3,4]console.log(b) //[0,1,2,3,4]? ?2、遞歸復制所有層級屬性
function deepCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; if (obj1 && typeof obj1 === "object") { for (var i in obj1) { if (obj1.hasOwnProperty(i)) { // 如果子屬性為引用數(shù)據(jù)類型,遞歸復制 if (obj1[i] && typeof obj1[i] === "object") { obj2[i] = deepCopy(obj1[i]); } else { // 如果是基本數(shù)據(jù)類型,只是簡單的復制 obj2[i] = obj1[i]; } } } } return obj2; } var obj1 = { a: 1, b: 2, c: { d: 3 } } var obj2 = deepCopy(obj1); obj2.a = 3; obj2.c.d = 4; alert(obj1.a); // 1 alert(obj2.a); // 3 alert(obj1.c.d); // 3 alert(obj2.c.d); // 4缺陷:當遇到兩個互相引用的對象,會出現(xiàn)死循環(huán)的情況,為了避免相互引用的對象導致死循環(huán)的情況,則應該在遍歷的時候判斷是否相互引用對象,如果是則退出循環(huán);
function deepCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; if (obj1 && typeof obj1 === "object") { for (var i in obj1) { var prop = obj1[i]; // 避免相互引用造成死循環(huán),如obj1.a=obj if (prop == obj1) { continue; } if (obj1.hasOwnProperty(i)) { // 如果子屬性為引用數(shù)據(jù)類型,遞歸復制 if (prop && typeof prop === "object") { obj2[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj2[i]); // 遞歸調用 } else { // 如果是基本數(shù)據(jù)類型,只是簡單的復制 obj2[i] = prop; } } } } return obj2; } var obj1 = { a: 1, b: 2, c: { d: 3 } } var obj2 = deepCopy(obj1); obj2.a = 3; obj2.c.d = 4; alert(obj1.a); // 1 alert(obj2.a); // 3 alert(obj1.c.d); // 3 alert(obj2.c.d); // 4// Object.create實現(xiàn)深拷貝1,但也只能拷貝一層function deepCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; if (obj1 && typeof obj1 === "object") { for (var i in obj1) { var prop = obj1[i]; // 避免相互引用造成死循環(huán),如obj1.a=obj if (prop == obj1) { continue; } if (obj1.hasOwnProperty(i)) { // 如果子屬性為引用數(shù)據(jù)類型,遞歸復制 if (prop && typeof prop === "object") { obj2[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { // 如果是基本數(shù)據(jù)類型,只是簡單的復制 obj2[i] = prop; } } } } return obj2; } var obj1 = { a: 1, b: 2, c: { d: 3 } } var obj2 = deepCopy(obj1); obj2.a = 3; obj2.c.d = 4; alert(obj1.a); // 1 alert(obj2.a); // 3 alert(obj1.c.d); // 3 alert(obj2.c.d); // 4// Object實現(xiàn)拷貝2,淺拷貝var obj1 = { a: 1, b: 2, c: { d: 3 } } var obj2 = Object.create(obj1); obj2.a = 3; obj2.c.d = 4; alert(obj1.a); // 1 alert(obj2.a); // 3 alert(obj1.c.d); // 4 alert(obj2.c.d); // 43、jquery的extends方法
$.extend([deep ], target, object1 [, objectN ])deep表示是否深拷貝,為true為深拷貝;為false,為淺拷貝。
target?Object類型 目標對象,其他對象的成員屬性將被附加到該對象上。
object1??objectN可選。Object類型 第一個以及第N個被合并的對象。?
let a = [0,1,[2,3],4]let b = $.extend(true, [], a)a[0] = 1a[2][0] = 1 // [1,1,[1,3],4]b // [0,1,[2,3],4]4、lodash函數(shù)庫實現(xiàn)深拷貝
let result = _.cloneDeep(test)5、Reflect法
// 代理法function deepClone(obj) { if (!isObject(obj)) { throw new Error('obj 不是一個對象!') } let isArray = Array.isArray(obj) let cloneObj = isArray ? [...obj] : { ...obj } Reflect.ownKeys(cloneObj).forEach(key => { cloneObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] }) return cloneObj}6、用slice實現(xiàn)對數(shù)組的深拷貝
// 當數(shù)組里面的值是基本數(shù)據(jù)類型,比如String,Number,Boolean時,屬于深拷貝// 當數(shù)組里面的值是引用數(shù)據(jù)類型,比如Object,Array時,屬于淺拷貝var arr1 = ["1","2","3"]; var arr2 = arr1.slice(0);arr2[1] = "9";console.log("數(shù)組的原始值:" + arr1 );console.log("數(shù)組的新值:" + arr2 );7.用concat實現(xiàn)對數(shù)組的深拷貝
// 當數(shù)組里面的值是基本數(shù)據(jù)類型,比如String,Number,Boolean時,屬于深拷貝var arr1 = ["1","2","3"];var arr2 = arr1.concat();arr2[1] = "9";console.log("數(shù)組的原始值:" + arr1 );console.log("數(shù)組的新值:" + arr2 );// 當數(shù)組里面的值是引用數(shù)據(jù)類型,比如Object,Array時,屬于淺拷貝var arr1 = [{a:1},{b:2},{c:3}];var arr2 = arr1.concat();arr2[0].a = "9";console.log("數(shù)組的原始值:" + arr1[0].a ); // 數(shù)組的原始值:9console.log("數(shù)組的新值:" + arr2[0].a ); // 數(shù)組的新值:9五 實現(xiàn)淺拷貝
for···in只循環(huán)第一層
// 只復制第一層的淺拷貝function simpleCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; for (let i in obj1) { obj2[i] = obj1[i]; } return obj2;}var obj1 = { a: 1, b: 2, c: { d: 3 }}var obj2 = simpleCopy(obj1);obj2.a = 3;obj2.c.d = 4;alert(obj1.a); // 1alert(obj2.a); // 3alert(obj1.c.d); // 4alert(obj2.c.d); // 4Object.assign方法
var obj = { a: 1, b: 2}var obj1 = Object.assign(obj);obj1.a = 3;console.log(obj.a) // 3直接用=賦值
let a=[0,1,2,3,4], b=a;console.log(a===b);a[0]=1;console.log(a,b);微信公眾號“學識鋪子” 回復 “拷貝”即可閱讀
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結
以上是生活随笔為你收集整理的js动态创建对象_JS深浅拷贝的深入浅出的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一加Ace 2V官方配置信息大汇总!就差
- 下一篇: 男子临时起意偷井盖 外卖小哥挺身而出上前