JavaScript中的浅拷贝

本文深入解析浅拷贝的概念,探讨其在对象和数组中的应用,通过实例演示如何使用Object.assign(), ES6的{…}

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.什么是浅拷贝

例如:根据原始A对象浅拷贝一个新的B对象出来

浅拷贝就是创建一个新对象B,这个对象B有着原始对象A属性值的一份精确拷贝。如果属性是基本类型,拷贝的就是A对象的基本类型的值;如果属性是引用类型,拷贝的就是A对象的内存(引用)地址 ,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。

浅拷贝只是解决了第一层的拷贝问题,拷贝第一层的基本类型值,以及第一层的引用类型地址,并没有递归拷贝第二层以后的属性。

2.浅拷贝使用方式

1.Object.assign()

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

如何判断一个属性是否可枚举?Object.keys() 可以判断,它返回一个包含所有给定对象自身可枚举属性名称的数组,如果返回的是空数组代表没有可枚举的属性。例如:Number, Boolean, Symbol …是不可枚举的

案例1:根据原始A对象浅拷贝一个新的B对象出来

// 1.Object.assign()  浅拷贝
let A = {
  name:'liujun',
  age:25,
  job:{
    name:'web',
    year:4
  }
}
console.log(A) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }
// 1.1 根据原始A对象浅拷贝一个新的B对象出来
let B = Object.assign({},A)
console.log(B) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }

// 1.2 修改A对象的两个name属性。发现B对象的job中的name属性也跟着改动了,说明B对象拷贝A对象job的引用地址
A.name = '刘军'
A.job.name = '前端开发'
console.log('--------------------------------')
console.log(A) // { name: '刘军', age: 25, job: { name: '前端开发', year: 4 } }
console.log(B) // { name: 'liujun', age: 25, job: { name: '前端开发', year: 4 } }

总结:只是解决了第一层的拷贝问题,拷贝第一层的基本类型值,以及第一层的引用类型地址

引用类型有 : Object Array Function Date RegExp …

案例2:根据原始 A1 和 A2 浅拷贝一个新的B对象出来

    // 1.Object.assign()  浅拷贝
    let A1 = 'LJ'
    let A2 = 25
    console.log(Object.keys(A1)) // [ '0', '1' ] 可枚举,拷贝成功
    console.log(Object.keys(A2)) // [] 不可枚举,拷贝失败

    // 1.1根据原始A1和A2浅拷贝一个新的B对象出来
    let B = Object.assign({},A1, A2)
    console.log(B) // { '0': 'L', '1': 'J' }

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

Number, Boolean, Symbol RegExp …是不可枚举的, 直接传递到 assign 中拷贝会失败,但是可以把它们封装到对象中传递即可以拷贝成功。

2.ES6的{…}语法

案例1:根据原始A对象浅拷贝一个新的B对象出来

// 1.Object.assign()  浅拷贝
let A = {
  name:'liujun',
  age:25,
  job:{
    name:'web',
    year:4
  }
}
console.log(A) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }
// 1.1 根据原始A对象浅拷贝一个新的B对象出来
let B = {...A}  // 这个与Object.assign({},A)的功能一样
console.log(B) // { name: 'liujun', age: 25, job: { name: 'web', year: 4 } }

// 1.2 修改A对象的两个name属性。发现B对象的job中的name属性也跟着改动了,说明B对象拷贝A对象job的引用地址
A.name = '刘军'
A.job.name = '前端开发'
console.log('--------------------------------')
console.log(A) // { name: '刘军', age: 25, job: { name: '前端开发', year: 4 } }
console.log(B) // { name: 'liujun', age: 25, job: { name: '前端开发', year: 4 } }

总结:只是解决了第一层的拷贝问题,拷贝第一层的基本类型值,以及第一层的引用类型地址。与Object.assign( {}, X ) 的功能一样

引用类型有 : Object Array Function Date RegExp …

3.[].slice()

案例1:根据原始A数组浅拷贝一个新的B数组出来

  // 1.使用 [].slice() 浅拷贝
  let A =[
      'arr1',
      [
        'java',
        'web'
      ]
    ]
  console.log(A) // [ 'arr1', [ 'java', 'web' ] ]
  // 1.1根据原始A对象浅拷贝一个新的B对象出来
  let B = A.slice()
  console.log(B) // [ 'arr1', [ 'java', 'web' ] ]

 // 1.2 修改A数组[1][1]的值。发现B数组的中[1][1]的值也跟着改动,说明B数组中二维数组拷贝的是引用地址
  A[0] = '刘军'
  A[1][1] = '前端开发' 
  console.log('--------------------------------')
  console.log(A) // [ '刘军', [ 'java', '前端开发' ] ]
  console.log(B) // [ 'arr1', [ 'java', '前端开发' ] ]

总结:只是解决了第一层的拷贝问题,拷贝第一层的基本类型值,以及第一层的引用类型地址

4.[].concat()

案例1:根据原始A数组浅拷贝一个新的B数组出来

  // 1.使用 [].slice() 浅拷贝
  let A =[
      'arr1',
      [
        'java',
        'web'
      ]
    ]
  console.log(A) // [ 'arr1', [ 'java', 'web' ] ]
  // 1.1根据原始A对象浅拷贝一个新的B对象出来
  let B = [].concat(A)
  console.log(B) // [ 'arr1', [ 'java', 'web' ] ]

 // 1.2 修改A数组[1][1]的值。发现B数组的中[1][1]的值也跟着改动,说明B数组中二维数组拷贝的是引用地址
  A[0] = '刘军'
  A[1][1] = '前端开发' 
  console.log('--------------------------------')
  console.log(A) // [ '刘军', [ 'java', '前端开发' ] ]
  console.log(B) // [ 'arr1', [ 'java', '前端开发' ] ]

总结:只是解决了第一层的拷贝问题,拷贝第一层的基本类型值,以及第一层的引用类型地址

5.编写浅拷贝函数

// 1.简单浅拷贝函数
function shallowCopy(source) {
    var target = {};
    for (var key in source) {
        if (Object.prototype.hasOwnProperty.call(source, key)) {
            target[key] = source[key];
        }
    }
    return target;
}

// 2.使用方法
let B = shallowCopy(A)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值