JS之深拷贝与浅拷贝

这篇具有很好参考价值的文章主要介绍了JS之深拷贝与浅拷贝。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、理解

 深拷贝 与 浅拷贝

 针对于 引用类型(Object,Array,Function) 来说的

浅拷贝:在栈中分配一块新内存,拷贝需要拷贝的值,

          对简单数据类型,就是拷贝值;对复杂数据类型,就是拷贝了一份栈内存储的堆内存的地址

 深拷贝:在堆中重新分配新内存,存储新的拷贝数据;

                在栈中分配新内存,存储新数据分配的堆的地址。

标准浅拷贝:

// =
let obj1 = obj
obj.a = '88888'
console.log(obj)
console.log( obj1)

结果:

JS之深拷贝与浅拷贝

实现方式:

 浅拷贝的实现方式:

        1. 基于Object.assign()

        2. 基于for in = 直接赋值

        3. ... 原地展开

 深拷贝的三种实现方式:

      1. 递归实现(重点)

      2. JSON.stringify + JSON.parse 方法

      3. JQuery的$extend方法(了解)

 其他奇怪的api方法?可能非真正的深拷贝

     1. slice 一维数组深拷贝,多维拷贝不彻底(针对数组)

     2. Object.assign

     3. Object.create

二、一些奇怪的api的使用及测试

1.Object.assign()

Object.assign用法:

  用于将源对象的所有可枚举属性到目标对象,返回目标对象

 至少需要两个对象做参数:Object.assign(目标对象, 源对象1,...)

 只要有一个参数不是对象,就会抛出TypeError错误

 如果有同名属性,后覆盖前;只复制自身属性(也会复制Symbol值的属性),不复制不可枚举/继承属性

 可用于: 为对象添加属性或方法;克隆对象;合并多个对象;为属性指定默认值

拷贝实现:

// Object.assign 
let obj = {
  a: 1,
  b: 2,
  c: [1, 2, 3],
  d: {
    g:777,
    s: {},
    f: function() { console.log('f')}
  }
}
let obj1 = Object.assign({}, obj)
console.log(obj1)

拷贝结果:

JS之深拷贝与浅拷贝

 拷贝测试:

对第一层的测试:

obj1.a = 666 // 对第一层的基本数据类型修改=>深拷贝
obj1.c = [] // 对第一层的引用数据类型 => 深拷贝
// obj1.c[0] = '000' // 对第一层的引用数据类型 内的某一项进行修改=>浅拷贝
//obj1.d.g = 8888 //
obj1.d.s.w = '9999999' // 对内层引用数据类型进行修改(添加)=>浅拷贝
console.log(obj)
console.log( obj1)

测试结果:

JS之深拷贝与浅拷贝

 其他测试:

obj1.c[0] = '000' // 对第一层的引用数据类型 内的某一项进行修改=>浅拷贝
obj1.d.g = 8888 // 对内层基础数据类型修改 => 浅拷贝
obj1.d.s.w = '9999999' // 对内层引用数据类型某一项 进行修改(添加)=>浅拷贝
obj1.d.f = {} // 对内层引用数据类型 整体修改 => 浅拷贝
console.log(obj)
console.log( obj1)

测试结果:

JS之深拷贝与浅拷贝

小总结:

 对拷贝的第一层的基础数据类型 实现了深拷贝(修改拷贝值,不影响新值);

 对深层数据,依然是浅拷贝,修改数据值会影响原数据

注意:当整体修改第一层引用数据后,新对象的整个引用数据的指向应该是修改后的,这时再对引用数据中某一项修改时,不会影响原来的对象;但直接对于第一层引用数据类型的某一项进行修改时,还是会影响原来的对象。

2.Object.create

api用法:

 方法用于 创建一个新对象,使用现有的对象来提供新创建的对象的proto

 参数: Object.create(proto新建对象的原型对象,[添加到新创建对象的可枚举属性])

 返回值:在指定原型对象上添加新属性后的对象

拷贝:

// 3. Object.create 浅拷贝
let obj1 = Object.create(obj)
console.log(obj1) // obj1 是一个空对象,其原型为obj;obj1.__proto__是obj的浅拷贝
console.log(obj1.__proto__ === obj) // true

运行结果:

JS之深拷贝与浅拷贝

浅拷贝,新对象的原型为旧对象

obj1 是一个空对象,其原型为obj;obj1.__proto__是obj的浅拷贝

3. ES6 ...扩展运算符

代码实现:

// ES6 扩展运算符
let obj1 = { ...obj }
console.log(obj1)

测试结果同Object.assign

4.slice+concat实现拷贝(针对数组)

slice:

实现及测试:

// 针对数组
let arr = ['a', 'b', 'c', {d:4}]

// slice
let arr1 = arr.slice(0)
// console.log(arr)
// console.log(arr1)

arr1[0] = '1'
arr1[3].d = '777'
console.log(arr)
console.log(arr1)

运行结果:

JS之深拷贝与浅拷贝

 可见,slice 对于数组中的基础数据类型,能够实现深拷贝,对于引用数据类型,无法实现深拷贝。

concat:

// concat
let arr1 = arr.concat()

// console.log(arr)
// console.log(arr1)

测试结果与slice相同。

三、实现深拷贝的三种方式

1. JSON.stringify + JSON.parse

拷贝实现:

let obj = {
  a: 1,
  b: 2,
  c: [1, 2, 3],
  d: {
    g:777,
    s: {w:'www'},
    f: function() { console.log('f')}
  },
  e: undefined,
  p: NaN,
  date:new Date()
}
// JSON.stringify + JSON.parse 方法
let obj1 = JSON.parse(JSON.stringify(obj))
console.log(obj)
console.log(obj1)

结果截图:

JS之深拷贝与浅拷贝

可见,拷贝对象无函数f、无undefined属性e,即该方法无法实现对函数、对undefined值的拷贝 ;

经测试,为深拷贝。

该方法存在的问题:

1.对象中有时间类型时,序列化后会变成字符串类型;

2.对象中有function、undefined类型的数据,会直接丢失;

3.对象中有NaN、Infinity、-Infinity时,序列化后会显示null;

4.对象循环引用时,会报错。

2.JQuery中的$.extend方法可以实现深拷贝(知道)

3.递归实现深拷贝(待升级完善版)

深拷贝的简单递归实现:

let obj = {
  a: 1,
  b: 2,
  c: [1, 2, 3],
  d: {
    g:777,
    s: {w:'www'},
    f: function() { console.log('f')}
  },
  e: undefined,
  p: NaN,
  date:new Date()
}

// 递归实现深拷贝--简单版()
function deepClone(obj) {
  let newObj = null
  // if (obj === null) return obj//???
  if (typeof obj == 'undefined') return undefined
  if (typeof obj === 'function') return obj//浅拷贝函数?
  if (obj.constructor == Date) return new Date(obj)
  if(obj.constructor == RegExp) return new RegExp(obj)
  
  if (typeof obj == 'object') {
    newObj = obj instanceof Array ? [] : {}
    for (let key in obj) {
      if (obj.hasOwnProperty(key)) {
        newObj[key] = deepClone(obj[key])
      }
    }
  } else {
    newObj = obj
  }
  return newObj
}

let obj1 = deepClone(obj)
console.log(obj)
console.log(obj1)

运行截图:

JS之深拷贝与浅拷贝

复杂版:

// 深拷贝 复杂版?
function checkType(target) {
  console.log(Object.prototype.toString.call(target).slice(8,-1))
  return Object.prototype.toString.call(target).slice(8,-1)
}

function deepClone2(data) {
  const obj = checkType(data) === 'Array' ? [] : {}
  let arr = ['Object','Array']
  if (arr.includes(checkType(data))) {
    for (let key in data) {
      let value = data[key]
      //value为简单类型,直接赋值
      if (!arr.includes(checkType(value))) {
        obj[key] = value
      } else {
        // 定义一个映射,初始化时,将data本身加入映射中
        const map = new WeakMap()
        // 如果拷贝的是复杂数据类型第一次拷贝后存入map
        // 第二次再遇到该值时,直接赋值为null,结束递归
        map.set(data, true)
        if (map.has(value)) {
          obj[key] = null
        } else {
          map.set(value, true);
          obj[key] = deepClone2(value)
        }
      }
    }
  } else {
    return data
  }
  return obj
}

let obj1 = deepClone2(obj)
console.log(obj)
console.log(obj1)

结果:

JS之深拷贝与浅拷贝

 文章来源地址https://www.toymoban.com/news/detail-484476.html

到了这里,关于JS之深拷贝与浅拷贝的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java中的深拷贝与浅拷贝

    深拷贝和浅拷贝是编程中常用的两种对象复制方式,它们在复制对象时处理对象内部引用的方式上有所不同。 浅拷贝 浅拷贝(Shallow Copy)只复制对象的顶层结构,而不复制对象内部的引用对象。换句话说,浅拷贝只复制对象的值类型字段和引用类型字段的引用,而不复制引

    2024年01月22日
    浏览(27)
  • 面试官:深拷贝与浅拷贝有啥区别?

    首先,明确一点深拷贝和浅拷贝是针对对象属性为对象的,因为基本数据类型在进行赋值操作时(也就是拷贝)是直接将值赋给了新的变量,也就是该变量是原变量的一个副本,这个时候你修改两者中的任何一个的值都不会影响另一个,而对象或者引用数据来说在进行浅拷贝

    2024年02月07日
    浏览(27)
  • 【Python】python深拷贝与浅拷贝详解(必须掌握)

    深拷贝和浅拷贝是python必须要掌握的内容,无论你是面试开发、测试、运维等职位,只要是python,深拷贝与浅拷贝是面试官常问的一个重要知识点。 (关注“测试开发自动化” 弓中皓,获取更多学习内容) 相同点: 无论深拷贝还是浅拷贝都会创建一个新对象。即:拷贝出来

    2024年03月25日
    浏览(29)
  • Java中的集合及深拷贝与浅拷贝

    Java是一种面向对象的编程语言,其中集合是常用的数据结构之一,具有方便快捷的特点。在Java开发中,我们常常需要对集合进行复制(拷贝)操作。但是,拷贝操作并不是简单的复制,而应该分为浅拷贝和深拷贝两种不同的方式,本文将分别介绍Java中集合的浅拷贝和深拷贝

    2024年02月07日
    浏览(25)
  • 深入探索前端之道:JavaScript深拷贝与浅拷贝的解析与实现

    前端开发中,数据的复制是一个常见的操作。尤其是在处理对象和数组时,我们需要考虑的是一个浅拷贝还是深拷贝。那么,什么是深拷贝和浅拷贝?它们在前端开发中有什么作用?如何实现这两种拷贝?这是我们在本文将讨论的问题。 浅拷贝 浅拷贝是一种数据复制方式,

    2024年02月10日
    浏览(27)
  • 深入理解 Java 引用类型:强壮、柔软、脆弱、虚无的力量

    🔭 大家好,我是 vnjohn,在互联网企业担任 Java 开发,CSDN 优质创作者 📖 推荐专栏:Spring、MySQL、Nacos、Java,后续其他专栏会持续优化更新迭代 🌲文章所在专栏:JVM 🤔 我当前正在学习微服务领域、云原生领域、消息中间件等架构、原理知识 💬 向我询问任何您想要的东西

    2024年02月11日
    浏览(25)
  • web前端面试-- js深拷贝的一些bug,特殊对象属性(RegExp,Date,Error,Symbol,Function)处理,循环引用weekmap处理

    本人是一个web前端开发工程师,主要是vue框架,整理了一些面试题,今后也会一直更新,有好题目的同学欢迎评论区分享 ;-) web面试题专栏:点击此处 在JavaScript中,深拷贝和浅拷贝是两种不同的对象复制方式。 浅拷贝是指将一个对象的引用复制给另一个对象,这意味着两个

    2024年02月07日
    浏览(31)
  • 前端JS代码中Object类型数据的相关知识

    获取Object类型数据的方式有两种: 方括号获取: Object[\\\"arg1\\\"] 点·获取: Object.arg1 前端遍历Object类型数据的方式 遍历JavaScript中的对象有几种方法,包括使用for…in循环、Object.keys()方法、Object.values()方法和Object.entries()方法。以下是每种方法的示例代码: Object对象中的日期类型

    2024年01月20日
    浏览(51)
  • js判断类型:typeof Object.prototype.toString instanceof constructor有什么区别?一文讲清楚

    相信很多小伙伴在使用js的过程中,经常会需要对js的数据类型进行判断,而js中可以对数据类型进行判断的方法有很多种,最常见的有typeof、Object.prototype.toString、instanceof、constructor这四种,那么他们有什么区别呢? 目录 js数据类型 typeof 为啥typeof会将null判断为object Object.pr

    2024年02月11日
    浏览(25)
  • js面包屑,如何制作面包屑,什么是面包屑,又如何去理解面包屑是什么呢,对于不会应该怎么办呢?这篇文章告诉你。

    🙂博主:锅盖哒 🙂文章核心: 带你了解原生js面包屑框架 目录大纲 1.面包屑的概念与框架地址 2.功能框架预览于介绍 框架效果预览: 页面架构代码预览: HTML页面预览:  权限验证介绍 3.面包屑的逻辑  下面就是面包屑逻辑 1.首先从login页面进入拿到渲染左侧列表的值 2

    2024年02月14日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包