欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

JavaScript深拷贝、浅拷贝

程序员文章站 2023-02-21 11:28:31
javascript深拷贝、浅拷贝 浅拷贝:浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅拷贝出来的对象也会相应改变。 深拷贝:开辟了一块新的内存存放地址和地址指向的对...

javascript深拷贝、浅拷贝

浅拷贝:浅拷贝只是复制了内存地址,如果原地址中的对象改变了,浅拷贝出来的对象也会相应改变。

深拷贝:开辟了一块新的内存存放地址和地址指向的对象,原地址的任何对象改变了,深拷贝出来的对象不变。

浅拷贝数组(只拷贝第一级数组):

1.直接遍历

var arr = [1,2,3,4];

function copy(arg){

var newarr = [];

for(var i = 0; i < arr.length; i++) {

newarr.push(arr[i]);

}

return newarr;

}

var newarry = copy(arr);

console.log(newarry);

newarry[0] = 10;

console.log(newarry); // [10,2,3,4]

console.log(arr) // [1,2,3,4]

2.slice

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

var copyarr = arr.slice();

copyarr[0] = 10;

console.log(copyarr); // [10,2,3,4]

console.log(arr); // [1,2,3,4]

slice(start,end),slice()方法返回一个数组中复制出来的元素组成新数组,start指起始元素下标,end指终止元素下标

当slice()不带任何参数时,默认返回一个和原数组一样的新数组

3.concat()

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

var copyarr = arr.concat();

copyarr[0] = 10;

console.log(copyarr); // [10,2,3,4]

console.log(arr); // [1,2,3,4]

array.concat(array1,array2,.......,arrayn),concat()方法用于连接两个或多个数组(不会改变原数组,返回被连接数组的副本)

然而如果第一级数组元素是对象或数组,上面三种方式都失效:

var arr = [

{number:1},

{number:2},

{number:3}

]

var copyarr = arr.slice();

copyarr[0].number = 10;

console.log(copyarr); // [{number: 100}, { number: 2 },{ number: 3 }]

console.log(arr); // [{number: 100}, { number: 2 }, { number: 3 }]

浅拷贝对象(如果对象中的值不为数组或对象)

1.直接遍历

var obj = {

name: "张三",

job: "学生"

}

function copy (arg) {

let newobj = {}

for(let item in obj) {

newobj[item] = obj;

}

return newobj;

}

var copyobj = copy(obj)

copyobj.name = "李四"

console.log(copyobj) // {name: '李四', job:: '学生'}

console.log(obj) // {name: '张三', job:: '学生'}

2.es6的object.assign

var obj = {

name: '张三',

job: '学生'

}

var copyobj = object.assign({},obj)

copyobj.name = '李四'

console.log(copyobj) // {name: '李四', job:: '学生'}

console.log(obj) // {name: '张三', job:: '学生'}

object.assign:用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target),并返回合并后的target

用法: object.assign(target, source1, source2); 所以 copyobj = object.assign({}, obj); 这段代码将会把obj中的一级属性都拷贝到 {}中,然后将其返回赋给copyobj

3.es6扩展运算符

var obj = {

name: '张三',

job: '学生'

}

var copyobj = {...obj}

copyobj.name = '李四'

console.log(copyobj)

console.log(obj)

扩展运算符(...)用于取出参数对象的所有可遍历属性,拷贝到当前对象之中

深拷贝

json.stringify()和json.parse()

用json.stringify把对象转成字符串,再用json.parse把字符串转成新的对象。

但是这种方法也有不少坏处,譬如它会抛弃对象的constructor。也就是深拷贝之后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成object。

这种方法能正确处理的对象只有 number, string, boolean, array, 扁平对象,即那些能够被 json 直接表示的数据结构。regexp对象是无法通过这种方式深拷贝。

也就是说,只有可以转成json格式的对象才可以这样用,像function、undefined、symbol、循环引用的对象没办法转成json。

var obj1 = { fun: function(){ console.log(123) } };

var obj2 = json.parse(json.stringify(obj1));

console.log(typeof obj1.fun);

// 'function'

console.log(typeof obj2.fun);

// 'undefined' <-- 没复制

使用递归函数实现一个深拷贝的方法:

function deepclone(obj) {

let 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] = deepclone(obj[key]);

} else {

objclone[key] = obj[key];

}

}

}

}

return objclone

}