搜索
写经验 领红包
 > 财经

javascipt深拷贝和浅拷贝的区别(js深拷贝和浅拷贝的使用场景)

导语:JavaScript中的深拷贝和浅拷贝

javascript深拷贝和浅拷贝的区别(js深拷贝和浅拷贝的使用场景)

什么是深拷贝/浅拷贝浅拷贝是创建一个新对象,这个对象具有原始对象属性值。如果属性是基本类型的话,拷贝的就是基本类型。如果属性是引用类型,拷贝的就是引用地址,改变了其中一个对象,就会影响到另外一个对象。深拷贝是将一个对象从内存中完整拷贝了一份,从堆内存中开辟了一个新的区域存放新对象,修改后不会影响原来的对象。赋值、深拷贝、浅拷贝的区别对象数组赋值给一个新的变量时,其实是赋的内存地址,而不是对象中的数据。所以修改一个将影响另外一个。
var person1 = {    name: &39;,    age: 20,    list: [1, 2, 3]}let arr = [4,5,6]var person2 = person1;person2.age = 22;person2.list = arr;person2.list[0] = &39;;console.log(person1);  // {name: &34;, age: 22, list:[&34;, 2, 3]}console.log(person2);  // {name: &34;, age: 22, list:[&34;, 2, 3]}console.log(arr);      // [&34;, 5, 6]
浅拷贝是重新在堆中创建内存,拷贝的基础类型互不影响,但是拷贝的引用类型共享同一个内存地址,会互相影响。
var person = {    name: &39;,    age: 20,    list: [1, 2, 3]}function shallowCopy(object) {    let temp = {};    for (const key in object) {        if (Object.hasOwnProperty.call(object, key)) {            temp[key] = object[key];        }    }    return temp;}var shallowPerson = shallowCopy(person)console.log(shallowPerson);  // {name: &34;, age: 20, list: [1, 2, 3]}shallowPerson.name = &39;;shallowPerson.list[0] = &39;;console.log(person);         // {name: &34;, age: 20, list: [&39;, 2, 3]}console.log(shallowPerson);  // {name: &34;, age: 20, list: [&39;, 2, 3]}
深拷贝是从堆内存中从新创建一个区域来存放新对象,并对对象中的子对象进行递归拷贝,互不影响。
var person = {    name: &39;,    age: 20,    list: [1, 2, 3]}function deepCopy(object){    let temp = Array.isArray(object) ? [] : {};    for (let key in object) {        temp[key] = typeof object[key] === &39; ? deepCopy(object[key]) : object[key]    }    return temp;}var shallowPerson = deepCopy(person)console.log(shallowPerson);             // {name: &34;, age: 20, list: [1, 2, 3]}shallowPerson.name = &39;;             shallowPerson.list[0] = &39;;        console.log(person);                    // {name: &34;, age: 20, list: [1, 2, 3]}console.log(shallowPerson);             // {name: &34;, age: 20, list: [&39;, 2, 3]}
浅拷贝的实现方式

ES6展开运算符 …

var person = {    name: &39;,    age: 20,    list: [1, 2, 3],    say:function(){console.log(&39;);},    check:new RegExp(&34;)}var user = { ...person}user.name = &39;console.log(user.name);         // 李四console.log(person.name);       // 张三

Object.assign()

var person = {    name: &39;,    age: 20,    list: [1, 2, 3]}var user = Object.assign({},person)console.log(user);  // // {name: &34;, age: 20, list: [1, 2, 3]}

lodash clone

var objects = [{ &39;: 1 }, { &39;: 2 }];var shallow = _.clone(objects);console.log(shallow[0] === objects[0]);// => true

Array concat

Array 的 concat方法不改变原数组,返回一个浅复制原数组的元素的新数组。如果元素是引用类型,就会拷贝这个引用的内存地址到新数组内。两个元素引用地址共享,所以如果发生改变将影响另外一个。如果元素是基本类型的话就会遵循浅拷贝的机制

var array = [1,[2,3,4],[5,6],{name:&39;}]let array_concat = array.concat()console.log(array_concat);  //  [1,2,3,[4,5,6],{name:&39;}]array_concat[1][0] = &39;console.log(array_concat[1]);  // [&34;, 3, 4]      console.log(array[1]);         // [&34;, 3, 4]array_concat[2] = [&39;,&39;,&39;]    // 这里之所以不一样,是因为改变了引用地址console.log(array_concat[2]);  // [&34;, &34;, &34;]console.log(array[2]);         // [5,6]array_concat[3].name = &39;;console.log(array_concat[3].name);  // 王五console.log(array[3].name);         // 王五

遍历复制

function shallowCopy(object) {    let temp = {};    for (const key in object) {        if (Object.hasOwnProperty.call(object, key)) {            temp[key] = object[key];        }    }    return temp;}
深拷贝的实现方式

JSON.parse/JSON.stringify

可以满足基本的使用,但是对于正则表达式类型、函数类型等无法进行深拷贝。

var person = {    name: &39;,    age: 20,    list: [1, 2, 3],    say:function(){console.log(&39;);},    check:new RegExp(&34;)}var user = JSON.parse(JSON.stringify(person));user.name = &39;;console.log(user.name);             // 李四console.log(person.name);           // 张三user.list[0] = &39;console.log(user.list);             // [&34;, 2, 3]console.log(person.list);           // [1, 2, 3]console.log(user.say);              // undefinedconsole.log(user.check);            // {}

lodash cloneDeep

var objects = [{ &39;: 1 }, { &39;: 2 }];var deep = _.cloneDeep(objects);console.log(deep[0] === objects[0]);// => false

递归遍历

var person = {    name: &39;,    age: 20,    list: [1, 2, 3],    say: function () { console.log(&39;); },    check: new RegExp(&34;)}function cloneDeep(object, hash = new WeakMap()) {    if (!isObject(object)) return object;    if(object instanceof Date) return new Date(object)    if(object instanceof RegExp) return new RegExp(object)    if (hash.has(object)) return hash.get(object)    let target = Array.isArray(object) ? [] : {};    hash.set(object, target);    for (const key in object) {        if (Object.hasOwnProperty.call(object, key)) {            if (typeof object[key] === &39;) {                target[key] = cloneDeep(object[key], hash)            } else {                target[key] = object[key];            }        }    }    return target;}function isObject(object) {    return typeof object === &39; && object != null;}var user = cloneDeep(person);user.name = &39;;console.log(user.name);             // 李四console.log(person.name);           // 张三user.list[0] = &39;            console.log(user.list);             // [&34;, 2, 3]console.log(person.list);           // [1, 2, 3]console.log(user.say);              // undefinedconsole.log(user.check);            // {}

本文内容由快快网络小樊整理编辑!