2021.06.17(理解js中的深拷貝和淺拷貝)
基本資料型別:賦值,賦值之後兩個變數互不影響
引用資料型別:賦址,兩個變數具有相同的引用,指向同一個物件,相互之間有影響
<script> //基本型別 var a = 100; var b = a; a = 200; console.log(a, b); // 200, 100 ,a b指向不同的資料 // 引用型別指向同一份資料 var a = { c: 1000 }; var b = a; a.c = 2000; console.log(a.c, b.c); // 2000, 2000 全是2000,a b指向同一份資料 </script>
通常在開發中並不希望改變變數 a 之後會影響到變數 b,這時就需要用到淺拷貝和深拷貝。
淺拷貝
建立一個新物件,這個物件有著原始物件屬性值的一份精確拷貝。如果屬性是基本型別,拷貝的就是基本型別的值,如果屬性是引用型別,拷貝的就是記憶體地址 ,
所以如果其中一個物件改變了這個地址,就會影響到另一個物件。
<script> function cloneShallow(source) { var target = {}; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } return target; } var a1 = { b: { c: {} } }; vara2 = cloneShallow(a1); // 淺拷貝 a2.b.c = { d: "1" }; console.log("a1---", a1); //{b:{c:{d:"1"}}} console.log("a2---", a2); //{b:{c:{d:"1"}}} var a5 = { b: { d: [1,2] } }; var a6 = cloneShallow(a5); // 淺拷貝 a6.b.d = [3,4]; console.log("a5---", a5); //{b:{d[3,4])) console.log("a6---", a6); //{b:{d[3,4])) // 注意:當object只有一層的時候,是深拷貝,例如如下: var a3 = { b:'9'}; var a4 = cloneShallow(a3); a4.b = '10'; console.log("a3---", a3); //{b:'9'} console.log("a4---", a4); //{b:'10'} </script>
Object.assign()
Object.assign() 方法可以把任意多個的源物件自身的可列舉屬性拷貝給目標物件,然後返回目標物件。注意,Object.assgin() 進行的是淺拷貝,拷貝的是物件的屬性的引用,而不是物件本身。
Object.assign(target, ...sources)
Array.prototype.concat()
Array.prototype.slice()
...obj 展開運算子
深拷貝
深拷貝會拷貝所有的屬性,並拷貝屬性指向的動態分配的記憶體。當物件和它所引用的物件一起拷貝時即發生深拷貝。深拷貝相比於淺拷貝速度較慢並且花銷較大。拷貝前後兩個物件互不影響
<script> function isObject(obj) { return typeof obj === "object" && obj != null; } function cloneDeep(source) { if (!isObject(source)) return source; // 非物件返回自身 var target = Array.isArray(source) ? [] : {}; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { if (isObject(source[key])) { target[key] = cloneDeep(source[key]); // 注意這裡 } else { target[key] = source[key]; } } } return target; } var obj = { title: "study", list: ["1", "2", "3"], }; var obj2 = cloneDeep(obj); obj2.title = "play"; obj2.list = ["3", "4"]; console.log("obj", obj); //title: "style",list: ["1", "2", "3"] console.log("obj2", obj2); //title: "play",list: ["3", "4"] </script>
JSON.parse(JSON.stringify(object))
JSON.stringify():將物件轉成 JSON 字串。
JSON.parse():將字串解析成物件。
通過 JSON.parse(JSON.stringify()) 將 JavaScript 物件轉序列化(轉換成 JSON 字串),
再將其還原成 JavaScript 物件,一去一來我們就產生了一個新的物件,而且物件會開闢新的棧,從而實現深拷貝。
注意
注意,該方法的侷限性:
1、不能存放函式或者 Undefined,否則會丟失函式或者 Undefined;
2、不要存放時間物件,否則會變成字串形式;
3、不能存放 RegExp、Error 物件,否則會變成空物件;
4、不能存放 NaN、Infinity、-Infinity,否則會變成 null;
5、……更多請自行填坑,具體來說就是 JavaScript 和 JSON 存在差異,兩者不相容的就會出問題。
函式庫 Lodash
cloneDeep() 方法
npm i --save lodash var _ = require('lodash'); var objects = [{ 'a': 1 }, { 'b': 2 }]; var deep = _.cloneDeep(objects); console.log(deep[0] === objects[0]); // => false
2021-06-17 11:18:29