日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > javascript >内容正文

javascript

js动态创建对象_JS深浅拷贝的深入浅出

發布時間:2023/12/15 javascript 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 js动态创建对象_JS深浅拷贝的深入浅出 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一 首先了解JavaScript中的基本數據類型

? ? ?基本數據類型:String,Number,Boolean,Null,Undefined

? ? ?引用數據類型:Araay,Date,RegExp,Function

二 基本數據類型和引用數據類型的區別?

? ? ?(1)它們保存的位置不同:基本數據保存在棧中,引用數據類型保存在堆內存中。JS對引用數據的操作其實操作對象的引用而不是實際的對象,也就是指向實際對象的內存地址,如果obj1拷貝了obj2,那么這兩個對象指向了同一堆內存對象,具體就是吧obj1棧內存中的引用地址復制了一份給obj2,所以他們指向了同一個堆內存對象。

? ? ? ??那為什么基本數據類型要存在棧內存中,而引用數據要存在堆內存中?

??? ? ? ?(1)堆比棧大,棧的查找速度比堆塊。

?? ? ? ? (2)基本數據類型比較的穩定,相對的話占用的內存比較小

? ? ? ? ?(3)引用數據類型一般都是動態的,而且可能是無限大,引用的值也經常改變,所以不能放在棧中,這樣會降低查找的速度,因此放在變量棧中的值應該是指向該對象再堆內存中的地址,地址的大小的固定的,所以吧他存在棧中對變量的性能沒有影響。

? ? ? JS一般在訪問存在堆內存的對象的時候是不能直接訪問的,所以在訪問對象的時候,要先獲取改對象再堆內存中的地址,在根據改地址去訪問該對象中的值。

? ??(2)基本數據類型可以使用typeof可以返回基本數據類型,但是Null會返回object,所以Null表示一個空對象指針;引用數據類型使用typeof會返回object,所以引用數據類型要用instanceof來檢測引用數據的類型。

? ? (3)定義引用數據類型需要使用new操作符,后面在跟一個構造函數來創建,或者使用對象字面量表示法創建對象。

? ? ? ? 使用new操作符創建對象

var obj1 = new Object();obj1.a = 1;

? ? ? ? 使用對象字面量表示法創建對象

var obj1 = { a: 1, b: 2}

基本數據類型 name和value值都是存儲在棧中

當b=a的時候

棧內存開辟了一個新內存出來,所以在修改a的值的時候不會影響到b的值

引用數據類型-name是存在棧中,value存在堆內存中,但是棧內存會提供一個引用地址指向該對象在堆內存中的值

當b=a拷貝時,其實復制的是a的引用地址,并不是堆內存中的值

當你修改a里面的值的時候,由于a與b指向的是同一個地址所以b也就受到了影響,這就是淺拷貝。

如果在堆內存中開辟了一個新的內存地址專門存在b的值的話,那就達到了深拷貝的效果了。

三 什么是深拷貝和淺拷貝

? ? ? 首先深拷貝和淺拷貝都只針對于引用類型的數據;淺拷貝只復制指向某個對象的指針,并不復制對象的本身,新原對象還是共享同一塊內存,但是深拷貝會創造一個一模一樣的新對象出來,新對象跟原對象不再共享同一塊內存地址,修改新對象也不會影響到原對象。

? ? ? ?區別:淺拷貝只復制對象的第一層屬性,深拷貝可以對對象的屬性進行遞歸復制。

四 實現深拷貝

? ?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)) { // 如果子屬性為引用數據類型,遞歸復制 if (obj1[i] && typeof obj1[i] === "object") { obj2[i] = deepCopy(obj1[i]); } else { // 如果是基本數據類型,只是簡單的復制 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

缺陷:當遇到兩個互相引用的對象,會出現死循環的情況,為了避免相互引用的對象導致死循環的情況,則應該在遍歷的時候判斷是否相互引用對象,如果是則退出循環;

function deepCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; if (obj1 && typeof obj1 === "object") { for (var i in obj1) { var prop = obj1[i]; // 避免相互引用造成死循環,如obj1.a=obj if (prop == obj1) { continue; } if (obj1.hasOwnProperty(i)) { // 如果子屬性為引用數據類型,遞歸復制 if (prop && typeof prop === "object") { obj2[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj2[i]); // 遞歸調用 } else { // 如果是基本數據類型,只是簡單的復制 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實現深拷貝1,但也只能拷貝一層function deepCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; if (obj1 && typeof obj1 === "object") { for (var i in obj1) { var prop = obj1[i]; // 避免相互引用造成死循環,如obj1.a=obj if (prop == obj1) { continue; } if (obj1.hasOwnProperty(i)) { // 如果子屬性為引用數據類型,遞歸復制 if (prop && typeof prop === "object") { obj2[i] = (prop.constructor === Array) ? [] : Object.create(prop); } else { // 如果是基本數據類型,只是簡單的復制 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實現拷貝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); // 4

3、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函數庫實現深拷貝

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實現對數組的深拷貝

// 當數組里面的值是基本數據類型,比如String,Number,Boolean時,屬于深拷貝// 當數組里面的值是引用數據類型,比如Object,Array時,屬于淺拷貝var arr1 = ["1","2","3"]; var arr2 = arr1.slice(0);arr2[1] = "9";console.log("數組的原始值:" + arr1 );console.log("數組的新值:" + arr2 );

7.用concat實現對數組的深拷貝

// 當數組里面的值是基本數據類型,比如String,Number,Boolean時,屬于深拷貝var arr1 = ["1","2","3"];var arr2 = arr1.concat();arr2[1] = "9";console.log("數組的原始值:" + arr1 );console.log("數組的新值:" + arr2 );// 當數組里面的值是引用數據類型,比如Object,Array時,屬于淺拷貝var arr1 = [{a:1},{b:2},{c:3}];var arr2 = arr1.concat();arr2[0].a = "9";console.log("數組的原始值:" + arr1[0].a ); // 數組的原始值:9console.log("數組的新值:" + arr2[0].a ); // 數組的新值:9

五 實現淺拷貝

for···in只循環第一層

// 只復制第一層的淺拷貝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); // 4

Object.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);

微信公眾號“學識鋪子” 回復 “拷貝”即可閱讀

創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎

總結

以上是生活随笔為你收集整理的js动态创建对象_JS深浅拷贝的深入浅出的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。