美文网首页
前端理论面试-数据拷贝

前端理论面试-数据拷贝

作者: Smallbore | 来源:发表于2019-12-30 15:32 被阅读0次

Object.assign()方法、slice()方法和concat()方法的拷贝

Object.assign()方法、slice()方法和concat()方法的拷贝 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

Object.assign() 方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

如果目标对象中的属性具有相同的键,则属性将被源对象中的属性覆盖。后面的源对象的属性将类似地覆盖前面的源对象的属性。

Object.assign 方法只会拷贝源对象自身的并且可枚举的属性到目标对象。该方法使用源对象的[[Get]]和目标对象的[[Set]],所以它会调用相关 getter 和 setter。因此,它分配属性,而不仅仅是复制或定义新的属性。如果合并源包含getter,这可能使其不适合将新属性合并到原型中。为了将属性定义(包括其可枚举性)复制到原型,应使用Object.getOwnPropertyDescriptor()和Object.defineProperty() 。

String类型和 Symbol 类型的属性都会被拷贝。

在出现错误的情况下,例如,如果属性不可写,会引发TypeError,如果在引发错误之前添加了任何属性,则可以更改target对象。

Object.assign 不会在那些source对象值为 null或 undefined 的时候抛出错误。

针对深拷贝,需要使用其他办法,因为 Object.assign()拷贝的是属性值。假如源对象的属性值是一个对象的引用,那么它也只指向那个引用。也就是说,如果对象的属性值为简单类型(如string, number),通过Object.assign({},srcObj);得到的新对象为深拷贝;如果属性值为对象或其它引用类型,那对于这个对象而言其实是浅拷贝的。

slice() 对于array对象的slice函数,返回一个数组的一段。(仍为数组)
arrayObj.slice(start, [end])

concat() 方法用于连接两个或多个数组。该方法不会改变现有的数组,而仅仅会返回被连接数组的一个副本。
语法:arrayObject.concat(arrayX,arrayX,......,arrayX)
说明:返回一个新的数组。该数组是通过把所有 arrayX 参数添加到 arrayObject 中生成的。如果要进行 concat() 操作的参数是数组,那么添加的是数组中的元素,而不是数组。

var arr1 = [{"name":"weifeng"},{"name":"boy"}];//原数组
var arr2 = [].concat(arr1);//拷贝数组
arr1[1].name="girl";
console.log(arr1);// [{"name":"weifeng"},{"name":"girl"}]
console.log(arr2);//[{"name":"weifeng"},{"name":"girl"}]

var a1=[["1","2","3"],"2","3"],a2;
a2=a1.slice(0);
a1[0][0]=0; //改变a1第一个元素中的第一个元素
console.log(a2[0][0]);  //影响到了a2

var b1=[["1","2","3"],"2","3"],b2;
b2=b1.slice(0);
b1[0][0]=0; //改变a1第一个元素中的第一个元素
console.log(b2[0][0]);  //影响到了a2

slice()和concat()这两个方法,仅适用于对不包含引用对象的一维数组的深拷贝。由于数组内部属性值为引用对象,因此使用slice和concat对对象数组的拷贝,整个拷贝还是浅拷贝,拷贝之后数组各个值的指针还是指向相同的存储地址。

Object.assign()方法、slice()方法和concat()方法的拷贝 当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。

使用JSON.stringify和JSON.parse实现深拷贝

JSON.stringify把对象转成字符串,再用JSON.parse把字符串转成新的对象
JSON.stringify()有一些局限,比如不能拷贝function,详见:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify

let newObj = JSON.parse(JSON.stringify(oldObj))

扩展运算符实现对象的深拷贝

var obj = {
  name: 'Smallbore',
  sex: 'man',
  old: '18'
}
var { ...obj2 } = obj
obj.old = '22'
console.log(obj)  // {name:'Smallbore',sex: 'man', old: '22'}
console.log(obj2) // {name:'Smallbore',sex: 'man', old: '18'}

注:当value是基本数据类型,比如String,Number,Boolean时,是可以使用拓展运算符进行深拷贝的。但是,当value是引用类型,比如Object,Array,这时使用拓展运算符进行深拷贝,得到的结果是和深拷贝的概念有矛盾的。主要是因为引用类型进行深拷贝也只是拷贝了引用地址。

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

function _deepClone(source) {
  let target;
  if (typeof source === 'object') {
    target = Array.isArray(source) ? [] : {}
    for (let key in source) {
      if (source.hasOwnProperty(key)) {
        if (typeof source[key] !== 'object') {
          target[key] = source[key]
        } else {
          target[key] = _deepClone(source[key])
        }
      }
    }
  } else {
    target = source
  }
  return target
}

lodash.cloneDeep()实现深拷贝

let _ = require('lodash');
let obj1 = {
    a: 1,
    b: { f: { g: 1 } },
    c: [1, 2, 3]
};
let obj2 = _.cloneDeep(obj1);

注:需要手动引入lodash依赖包。

相关文章

  • 前端理论面试-数据拷贝

    Object.assign()方法、slice()方法和concat()方法的拷贝 Object.assign()...

  • 2020-01-19做些js的数组练习吧

    1.前端面试必问之数组去重 前端面试必问之数组去重 2.前端面试必问之深拷贝浅拷贝 3.

  • 前端面试必问之深拷贝浅拷贝

    深拷贝、浅拷贝是前端面试的高频题目,要想知道它们的区别我们需要先搞懂它们的定义。 浅拷贝: 创建一个新对象,这个对...

  • 前端面试-深拷贝

    递归 JSON

  • 前端理论面试--VUE

    vue双向绑定的原理(详细链接) VUE实现双向数据绑定的原理就是利用了 Object.definePropert...

  • 前端理论面试-总结

    对W3C标准,对表现与数据分离、Web语义化等有深刻理解 W3C是指万维网联盟(World Wide Web Co...

  • 手写实现深度拷贝

    手写实现深度拷贝 本文参考:面试题之如何实现一个深拷贝 基础理论 拷贝的基础是赋值,在 js 中,将一个变量赋值给...

  • JS中的深浅拷贝

    这几乎是前端面试的高频问题。 什么是深浅拷贝? 浅拷贝 把对象a的值赋值给b,再修改b.name的值, a.nam...

  • 前端理论面试- 请求数据深度探究

    最近总是去腾讯面试,结果都挂掉了,失去了生活的希望,好想去远方。。。无奈还欠着太多贷款,还没有结婚生娃,之后咬着牙...

  • 目录

    软件工程师基本技能 Python基础 Python常用数据结构Python面试题汇总深拷贝和浅拷贝super正则表...

网友评论

      本文标题:前端理论面试-数据拷贝

      本文链接:https://www.haomeiwen.com/subject/kpkmoctx.html