博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
javascript中的深拷贝与浅拷贝
阅读量:2073 次
发布时间:2019-04-29

本文共 5172 字,大约阅读时间需要 17 分钟。

javascript中的深拷贝与浅拷贝

欢迎访问我的博客,祝码农同胞们早日走上人生巅峰,迎娶白富美~~~

声明:参考文章:

看这个深拷贝浅拷贝之前,先要对javascript中不同数据类型之间的传值有一定的了解

javascript中不同数据类型之间的传值

javascript中数据类型简单分为基本数据类型引用数据类型

基本数据类型:String,Number,Boolean等

引用数据类型:Array,Object等

基本数据类型引用数据类型最大的区别在于他们的处安置方式不同

基本数据类型的传值

1 2 3 4 5 6 7 8
var a = 1 var b = a // a = 1 // b = 1 b = 2 // a = 1 // b = 2 // a 的原始值不会被修改

引用数据类型的传值

1 2 3 4 5 6 7 8 9 10 11
var people = {
name: 'zhangsan', age: 10 } var people2 = people console.log(people.age) // 10 console.log(people2.age) // 10 people2.age = 100 console.log(people.age) // 100 console.log(people2.age) // 100 // people 的值被修改了

这里发现 people 的值被修改了,因为这就是引用传值,他们本身指向了同一个引用,即地址,修改的是同一个地址中的值,所以会发生想修改people2的时候,却无意间影响到了people的原始值,这就是浅拷贝

深拷贝和浅拷贝

如上例子,简单粗暴的理解就是当people2复制了people,而当people2修改时,people一块被修改了,这叫浅拷贝,当people2修改时,而people没有被修改,这叫深拷贝

但是,本意不想修改people,只想修改people2的,却造成了这样的错误,如何避免呢?

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var people = {
name: 'zhangsan', age: 10 } var people2 = {
name: people.name, age: people.age } var people2 = people console.log(people.age) // 10 console.log(people2.age) // 10 people2.age = 100 console.log(people.age) // 10 console.log(people2.age) // 100 // people 的值没有被修改

这个时候是深拷贝,但是总不能总不能这么复杂吧,要一个一个的拷贝到people2对象中,很麻烦,容易出错,这时候就要有深拷贝的方法浅拷贝的方法

浅拷贝的实现

  1. 赋值,上面介绍传值的时候也有的方法,就是直接赋值的操作,可以参照上面的例子

  2. Object.assign()

    1. 介绍Object.assignES6的新函数,Object.assign() 方法可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象,但是 Object.assign() 进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身
    2. 语法Object.assign(target, ...sources)
    3. 参数target:目标对象,sources:任意多个源对象
    4. 返回值:返回目标对象
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
    var people = {
    name: 'zhangsan', age: 10, zhangsan: {
    say: function () {
    console.log('hello') }, height: 180 } } var people2 = Object.assign({}, people) console.log(people.zhangsan.height) // 180 console.log(people2.zhangsan.height) // 180 people2.zhangsan.height = 181 console.log(people.zhangsan.height) // 181 console.log(people2.zhangsan.height) // 181 // people 的值被修改了

    但是当Object.assign()去处理只有一层的拷贝的时候,再看看

    1 2 3 4 5 6 7 8 9 10 11
    var people = {
    name: 'zhangsan', age: 10 } var people2 = Object.assign({}, people) console.log(people.age) // 10 console.log(people2.age) // 10 people2.age = 100 console.log(people.age) // 10 console.log(people2.age) // 100 // people 的值没有被修改

    总结

    Object.assign()去处理一层的拷贝的时候,可以达到,修改people2不影响people,但是当Object.assign()进行深一层的拷贝的时候,修改people2会影响people

深拷贝的实现

  1. 手动复制,这在上面介绍传值的时候,有过例子,可以参照上面的例子,缺点:很麻烦
  2. 对象只有一层的话,可以用上面的Object.assign()去处理
  3. 利用JSON字符串的基本类型赋值
    1. 优点:理解简单,用起来也简单
    2. 缺点:只适用于那些能够被 json 直接表示的数据结构,且它会抛弃对象的constructor
1 2 3 4 5 6 7 8
var people = { zhangsan: { age: 10 } } var people2 = JSON.parse(JSON.stringify(people)) console.log(people.zhangsan.age) // 10 console.log(people2.zhangsan.age) // 10 people2.zhangsan.age = 100 console.log(people.zhangsan.age) // 10 console.log(people2.zhangsan.age) // 100 // people.zhangsan.age 原始值没被修改
  1. 递归拷贝
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
function deepClone(a, b) {      var obj = b || {}     for (var i in a) {            if (typeof a[i] === 'object') {
obj[i] = (a[i].constructor === Array) ? [] : {} arguments.callee(a[i], obj[i]) } else {
obj[i] = a[i] } } return obj } var str = {} var obj = { a: {
a: "hello", b: 21} } deepClone(obj, str) console.log(str.a)

上述方法已经能够实现,深拷贝,但是当两个对象相互引用的时候,问题就来了,会出现死循环

为了避免相互引用的对象导致死循环的情况,则应该在遍历的时候判断是否相互引用对象,如果是则退出循环

改进如下

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
function deepClone(a, b) {      var obj = b || {}      for (var i in a) {            var prop = a[i]        // 避免相互引用对象导致死循环,如a.a = a的情况     if(prop === obj) {     // 避免相互引用对象导致死循环,如a.a = a的情况            continue     }            if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {} arguments.callee(prop, obj[i]) } else {
obj[i] = prop } } return obj } var str = {} var obj = { a: {
a: "hello", b: 21} } deepClone(obj, str) console.log(str.a)
  1. 使用Object.create()方法

Object.create()方法的原理其实就和上面递归拷贝实现改进版是一样的

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var people = {
name: 'zhangsan', age: 10, zhangsan: {
say: function () {
console.log('hello') }, height: 180 } } var people2 = Object.create(people) console.log(people.zhangsan.height) // 180 console.log(people2.zhangsan.height) // 180 people2.zhangsan.height = 181 console.log(people.zhangsan.height) // 180 console.log(people2.zhangsan.height) // 181 // people 的值没被修改
  1. JQuery 中的 $.extend
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
var $ = require('jquery') var people = {
name: 'zhangsan', age: 10, zhangsan: {
say: function () {
console.log('hello') }, height: 180 } } var people2 = $.extend(true, {}, people) console.log(people.zhangsan.height) // 180 console.log(people2.zhangsan.height) // 180 people2.zhangsan.height = 181 console.log(people.zhangsan.height) // 180 console.log(people2.zhangsan.height) // 181 // people 的值没被修改

转载地址:http://axtmf.baihongyu.com/

你可能感兴趣的文章
面试心得与总结---BAT、网易、蘑菇街
查看>>
如何面试有2年java工作经验的应聘人员
查看>>
Java实现简单的递归操作
查看>>
HashMap 和 HashTable 到底哪不同 ?
查看>>
Java实现简单的递归操作
查看>>
Struts2工作原理和执行流程图
查看>>
在线预览Word,Excel~
查看>>
hibernate延迟加载(get和load的区别)
查看>>
关于文件拷贝效率问题
查看>>
MyBatis分页插件PageHelper的使用
查看>>
【MyBatis学习01】宏观上把握MyBatis框架
查看>>
【MyBatis学习02】走进MyBatis的世界
查看>>
【MyBatis学习03】原始dao开发方法及其弊端
查看>>
【MyBatis学习04】mapper代理方法开发dao
查看>>
【MyBatis学习05】SqlMapConfig.xml文件中的配置总结
查看>>
【MyBatis学习06】输入映射和输出映射
查看>>
【MyBatis学习07】动态sql
查看>>
【MyBatis学习08】高级映射之一对一查询
查看>>
【MyBatis学习09】高级映射之一对多查询
查看>>
【MyBatis学习10】高级映射之多对多查询
查看>>