js深拷贝和浅拷贝的区别
发布时间:2025-05-24 10:23:11 发布人:远客网络
一、js深拷贝和浅拷贝的区别
1.浅拷贝:复制一份引用,所有引用对象都指向一份数据,并且都可以修改这份数据。
2.深拷贝(复杂):复制变量值,对于非基本类型的变量,则递归至基本类型变量后,再复制。
在使用JavaScript对数组进行操作的时候,我们经常需要将数组进行备份,事实证明如果只是简单的将它赋予其他变量,那么我们只要更改其中的任何一个,然后其他的也会跟着改变,这就导致了问题的发生。
var arr= ["One","Two","Three"]; var arrto= arr; arrto[1]="test"; document.writeln("数组的原始值:"+ arr+"<br/>");//Export:数组的原始值:One,test,Three document.writeln("数组的新值:"+ arrto+"<br/>");//Export:数组的新值:One,test,Three
像上面的这种直接赋值的方式就是浅拷贝,很多时候,这样并不是我们想要得到的结果,其实我们想要的是arr的值不变,不是吗?
var arr= ["One","Two","Three"]; var arrtoo= arr.slice(0); arrtoo[1]="set Map"; document.writeln("数组的原始值:"+ arr+"<br/>");//Export:数组的原始值:One,Two,Three document.writeln("数组的新值:"+ arrtoo+"<br/>");//Export:数组的新值:One,set Map,Three
var arr= ["One","Two","Three"]; var arrtooo= arr.concat(); arrtooo[1]="set Map To"; document.writeln("数组的原始值:"+ arr+"<br/>");//Export:数组的原始值:One,Two,Three document.writeln("数组的新值:"+ arrtooo+"<br/>");//Export:数组的新值:One,set Map To,Three
var a={name:'yy',age:26}; var b=new Object(); b.name=a.name; b.age=a.age; a.name='xx'; console.log(b);//Object{ name="yy", age=26} console.log(a);//Object{ name="xx", age=26}
就是把对象的属性遍历一遍,赋给一个新的对象。
var deepCopy= function(source){ var result={}; for(var key in source){ result[key]= typeof source[key]==='object'? deepCoyp(source[key]): source[key];} return result;}
jQuery.extend= jQuery.fn.extend= function(){//1.将extend方法扩展到JQ(函数)下边:扩展静态方法//2. jQuery.fn.extend把extend扩展到jq.fn下且jQuery.fn= jQuery.prototype扩展实例方法// 1.2.功能相似 var options, name, src, copy, copyIsArray, clone,//定义一些变量 target= arguments[0]||{},//目标元素是【0】第一个元素$.extend( a,{ name:'hello'},{ age: 30}); i= 1,//第一个元素的位置 length= arguments.length,//第一个个对象的元素 deep= false;//是否是深拷贝默认 false不是// Handle a deep copy situation看是不是深拷贝情况 if( typeof target==="boolean"){//是布尔值 deep= target; target= arguments[1]||{};//目标元素是第二个$.extend( true, a, b)// skip the boolean and the target i= 2;}// Handle case when target is a string or something(possible in deep copy)看参数正确不 if( typeof target!=="object"&&!jQuery.isFunction(target)){//当目标不是对象或者不是函数的时候 target={};//变成一个空的jason}// extend jQuery itself if only one argument is passed看是不是插件情况 if( length=== i){//只写了一个对象要把这个对象扩展到jq源码上静态方法或者是实例方法 target= this;//this是$或者$();--i;}//可能有多个对象情况 for(; i< length; i++){// Only deal with non-null/undefined values if((options= arguments[ i ])!= null){//看后边的对象是否都有值// Extend the base object for( name in options){ src= target[ name ]; copy= options[ name ];// Prevent never-ending loop if( target=== copy){//防止循环引用 continue;//跳出本次循环继续执行//$.extend( a,{ name: a}));循环引用 a也是一个对象}// Recurse if we're merging plain objects or arrays深拷贝 if( deep&& copy&&( jQuery.isPlainObject(copy)||(copyIsArray= jQuery.isArray(copy)))){//是深拷贝且需有var b={ name:{ age: 30}};且b必须是对象自变量(jason)或者是个数组//递归 if( copyIsArray){//数组 copyIsArray= false; clone= src&& jQuery.isArray(src)? src: [];//定义一个空数组} else{//jason clone= src&& jQuery.isPlainObject(src)? src:{};//看原有的属性有没有且是不是jason定义一个空jason}// var a={ name:{ job:'it'}};看有没有原有的属性有的话在原有的上边添加// var b={ name:{age: 30}};//$.extend( true, a, b);//a继承b// console.log( a); a{ name:{ job:'it',age: 30}}如果只有一个{}则只有,age: 30// Never move original objects, clone(a) them target[ name ]= jQuery.extend( deep, clone, copy);//调用函数本身进行进一步的递归处理// Don't bring in undefined values浅拷贝} else if( copy!== undefined){ target[ name ]= copy;//直接复制因为里边没有对象}}}}// Return the modified object return target;};
二、JSON.parse,JSON.stringify 深浅拷贝的缺陷
在深入探讨JSON.parse和JSON.stringify在进行深拷贝时可能遇到的缺陷之前,让我们先理解一下这两个方法的基本工作原理。
JSON.parse和JSON.stringify是JavaScript中用于序列化和反序列化对象的函数。JSON.stringify将JavaScript对象转换为JSON字符串,而JSON.parse则将JSON字符串解析回JavaScript对象。理论上,这应该能够帮助我们进行对象的深拷贝。
然而,在实际应用中,当尝试使用这两种方法进行深拷贝时,可能会遇到一些问题,导致一些属性被忽略或丢失。下面将详细分析这种缺陷的原因以及如何识别和解决。
首先,让我们通过一个简单的示例来了解可能的缺陷。
假设我们有一个自定义对象,包含一些属性和方法。当我们尝试使用JSON.stringify将此对象序列化为JSON字符串,然后使用JSON.parse将JSON字符串反序列化回JavaScript对象时,虽然表面上看起来对象的结构得以保留,但实际上某些属性可能并未正确复制。这可能是由于JSON.stringify和JSON.parse在处理特定类型的值时的限制所导致的。
例如,如果对象中包含一些非基本类型值(如函数、正则表达式等),在使用JSON.stringify序列化时,这些复杂类型的值可能会被忽略或表示为特殊的字符串形式。当使用JSON.parse反序列化时,这些值可能无法正确恢复,导致原对象的部分属性丢失。
更深层次的原因在于,JSON.stringify仅能序列化基本类型和可序列化的非基本类型值(如数组、对象、布尔值、数字、字符串、null和undefined)。对于复杂类型值,如函数或正则表达式,JSON.stringify无法准确地将其表示为JSON格式,因此在序列化和反序列化过程中可能会导致信息丢失。
为了解决这个问题,可以采取以下策略:
1.使用深层复制库:有一些库(如lodash的_.cloneDeep或deep-copy.js)提供了更强大的深层复制功能,能够正确复制所有类型的值,包括非基本类型和复杂类型。
2.手动处理特定类型:如果知道对象中包含特定类型值,可以手动处理这些值。例如,对于函数或正则表达式,可以将它们的引用复制到新对象中,而不是尝试将它们序列化为JSON。
总之,JSON.stringify和JSON.parse是JavaScript中用于序列化和反序列化对象的强大工具。然而,在进行深拷贝时,它们可能会遇到一些限制,导致属性丢失或不正确复制。通过使用深层复制库或手动处理特定类型值,可以解决这些问题,确保对象的完整复制。
三、深入理解JavaScript之深浅拷贝!
1、JavaScript中的深浅拷贝是对对象或数组进行复制的操作,用于在修改原始对象时不会影响到已复制的对象。浅拷贝只复制对象的一层,而深拷贝会复制整个对象的所有层次。
2、浅拷贝:定义:浅拷贝只复制对象的一层属性。如果对象中有引用类型的属性,复制出来的对象和原对象会共享这些引用类型的属性。适用场景:适用于简单的数据类型对象。实现方式: Object.assign:将源对象的所有可枚举属性复制到目标对象。 Spread operator:将一个对象的属性复制到新的对象中。 Array.slice:对数组进行浅拷贝,返回一个新数组。 Array.concat:不传入参数时,对数组进行浅拷贝,返回一个新数组。
3、深拷贝:定义:深拷贝是对对象或数组进行递归复制,复制整个对象的所有层次。这样可以避免对象中的引用类型属性共享的问题。适用场景:表单数据处理,确保数据完整无误地发送。 Redux状态管理,保持应用程序的稳定性和可维护性。对象的缓存和比较,避免意外的修改和引用相等的问题。数据结构的变换,避免修改原始数据。实现方式: JSON.parse和 JSON.stringify:将对象转换为 JSON字符串再转换回对象,但这种方法有局限性,不能处理函数、正则表达式和日期等非 JSON标准的数据类型,也不能处理循环引用的对象。递归实现:在对象或数组的每一层进行复制,生成一个新的独立的对象。
4、总结:在JavaScript中,深浅拷贝的选择取决于具体的场景和数据结构的复杂性。浅拷贝适用于简单的数据类型对象,而深拷贝适用于复杂的数据结构和需要保持数据独立性的场景。