深复制,指的是在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中应用广泛,通过深复制可以避免对原对象的影响,保证程序的正确性。