由於對象的是經過指針仔細內存地址的,因此對象的拷貝不能像變量通常簡單的賦值,對象的賦值只是將指針的地址賦值過去而已,修改屬性值會對全部指向這個內存地址的對象的屬性值都會被改變,見下面的例子:javascript
// 變量賦值 var a = 5; var b = a; // 修改b不會對a形成影響 b=10; > a > 5 // 對象賦值 var obj = { a: '5', b: '10', c: { d: 1 } } var obj1 = obj // 修改obj1.a會對obj.a形成影響 obj1.a = 9 > obj.a > 9
因此當你使用object(array也是object的一種特殊形式)時,想複製一個object,但兩個object互不影響時,這就須要咱們說的淺拷貝和深拷貝了java
// object數據中只能有基本的數據類型(String,Number,Boolean,Array,object,null,undefined),其它數據會丟失,但不會報錯 obj1 = JSON.parse(JSON.stringify(obj))
基於Object的特殊性,在對對象進行簡單的拷貝,只拷貝第一層級的屬性,這種拷貝就是淺拷貝。segmentfault
function Copy(source, obj) { for (let key in obj) { source[key] = obj[key] } return source } Copy(obj1, obj) obj1.a=10 obj1.c.d=100 // 淺拷貝對第一層的屬性進行了拷貝,因此obj.a不受影響 > obj.a = 9 // 可是obj.c.d是第二層級的屬性,它受到了影響,它的值被改變了 > obj.c.d =100
注意:遞歸遍歷可能爆棧,通常不會出現這種狀況,除非對象的深度達到10000+prototype
// 判斷數據類型的方法--更新於2019-03-28 function isType(data, type) { return Object.prototype.toString.call(data) === '[object ' + type + ']' } // extendEasy實現深拷貝;extendSuper在深拷貝的基礎上實現多個繼承相似(source, obj1, obj2, obj3 ...) function extendSuper () { var arg = arguments for (let i = 1; i < arg.length; i++) { arg[0] = extendEasy(arg[0], arg[i]) } return arg[0] } // 實現深拷貝 function extendEasy (source, obj) { for (let key in obj) { // 原來使用instanceof判斷類型會存在BUG if (isType('Object',obj[key])) { source[key] = {} source[key] = extendEasy(source[key], obj[key]) } if (isType(' Array',obj[key])) { source[key] = [] source[key] = extendEasy(source[key], obj[key]) } source[key] = obj[key] } return source }
注意:下面代碼中Object.isType的實現方式-->https://segmentfault.com/a/11...
深度和廣度:pop跟push決定了深度優先,廣度優先請用shift和push指針
/* * @param target object 非必填,默認{} * @param source object 必填 * * */ function copyObject() { let root = {} const obj = arguments[arguments.length] if(!Object.isType(obj, "Object") && !Object.isType(obj, "Array")) { throw "source not Object" } if(arguments.length >= 2 && (Object.isType(arguments[0], "Object") || Object.isType(arguments[0], "Array"))) { root = arguments[0] } else { if(Object.isType(arguments[0], "Array")) { root = [] } } // 棧 const arr = [ { // key: undefined, parent: root, data: obj } ] while (arr.length) { // arr: pop跟push決定了深度優先,廣度優先請用shift和push const o = arr.pop() // if(o.key === undefined) { // o // } for (let item in o.data){ if (Object.isType(o.data[item], "Array")){ o.parent[item] = [] arr.push({ key: item, parent: o.parent[item], data: o.data[item] }) } else if (Object.isType(o.data[item], "Object")) { o.parent[item] = {} arr.push({ key: item, parent: o.parent[item], data: o.data[item] }) } // 若是對其它類型支持請在這裏拓展 else { o.parent[item] = o.data[item] } } } return root }