深復制,指的是在JavaScript中將一個對象的所有屬性都復制到一個新對象中,同時也復制了屬性值的所有子屬性。所以,在新對象中,原始和復制對象是獨立的,即使復制對象的原型也是復制的。
對于簡單數據類型如string、number等,深復制比較簡單,只需要進行賦值即可。但是對于引用類型,僅僅復制它的地址并不是真正的復制,因為這仍然會導致原始對象和復制對象的屬性值指向相同的對象。
var obj1 = { name: 'Tom', age: 18, skills: ['js', 'html', 'css'] }; var obj2 = obj1; obj2.name = 'Tony'; console.log(obj1.name); // Tony
上述代碼中,obj1和obj2指向同一個對象。當我們修改obj2的name屬性時,obj1的name屬性也會被修改。
因此,我們需要使用深復制實現真正的復制。下面是一些實現深復制的方法。
方法一:JSON.parse(JSON.stringify(obj))
這種方法利用了JSON對象的解析和字符串化能力。首先,將對象通過JSON.stringify轉成字符串,再通過JSON.parse轉回對象,此時對象已經是一個完整的深復制對象。
var obj1 = { name: 'Tom', age: 18, skills: ['js', 'html', 'css'] }; var obj2 = JSON.parse(JSON.stringify(obj1)); obj2.skills.push('node'); console.log(obj1.skills); // ['js', 'html', 'css'] console.log(obj2.skills); // ['js', 'html', 'css', 'node']
JSON.parse和JSON.stringify都可以處理大部分JavaScript對象,但不支持一些對象,比如Date和Function。如果對象中包含這些類型,就需要使用其他方法。
方法二:遞歸復制
這種方法的實現是通過遞歸遍歷對象的屬性值,如果屬性值是引用類型,則遞歸進行復制,直到復制到所有的引用類型。
function deepCopy(obj){ if(obj === null || typeof obj !== 'object'){ return obj; } var clone = Array.isArray(obj) ? [] : {}; for(var attr in obj){ if(obj.hasOwnProperty(attr)){ clone[attr] = deepCopy(obj[attr]); } } return clone; } var obj1 = { name: 'Tom', age: 18, skills: ['js', 'html', 'css'] }; var obj2 = deepCopy(obj1); obj2.skills.push('node'); console.log(obj1.skills); // ['js', 'html', 'css'] console.log(obj2.skills); // ['js', 'html', 'css', 'node']
這種方法比較通用,可以支持對象中包含Date和Function等類型,但是需要寫遞歸,稍微復雜一些。
總之,深復制在JavaScript中應用廣泛,通過深復制可以避免對原對象的影響,保證程序的正確性。