JS 中深拷贝的几种实现方法

JavaScript010

JS 中深拷贝的几种实现方法,第1张

JS 中深拷贝的几种实现方法

1、使用递归的方式实现深拷贝

//使用递归的方式实现数组、对象的深拷贝

function deepClone1(obj) {

//判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝

var objClone = Array.isArray(obj) ? [] : {}

//进行深拷贝的不能为空,并且是对象或者是

if (obj &&typeof obj === "object") {

for (key in obj) {

if (obj.hasOwnProperty(key)) {

if (obj[key] &&typeof obj[key] === "object") {

objClone[key] = deepClone1(obj[key])

} else {

objClone[key] = obj[key]

}

}

}

}

return objClone

}

2、通过 JSON 对象实现深拷贝

//通过js的内置对象JSON来进行数组对象的深拷贝

function deepClone2(obj) {

var _obj = JSON.stringify(obj),

objClone = JSON.parse(_obj)

return objClone

}

JSON对象实现深拷贝的一些问题

* 无法实现对对象中方法的深拷贝

3、通过jQuery的extend方法实现深拷贝

var array = [1,2,3,4]

var newArray = $.extend(true,[],array)

4、Object.assign()拷贝

当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

5、lodash函数库实现深拷贝

lodash很热门的函数库,提供了 lodash.cloneDeep()实现深拷贝

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的值不变,不是吗?

方法一:js的slice函数

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

方法二:js的concat方法

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中的例子:

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 <lengthi++ ) { // 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 {//jasonclone = 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) themtarget[ 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 }