JavaScript高级——浅拷贝和深拷贝

直接把一个对象赋值给新对象,赋值的是地址,a和b指向堆内存中的同一个对象,所以改变一者,另一者也会改变。

var obj1 = {
	name:'zs',
	age:16
}
var obj2 = obj1
obj2.name = 'ls'
console.log(obj1.name) // 'ls'

可以用浅拷贝和深拷贝解决这个问题

浅拷贝

浅拷贝,只拷贝第一层的原始类型值,和第一层的引用类型地址。

方法一 Object.assign({}, obj1)
var obj1 = {
	name:'zs',
	age:16
}
var obj2 = Object.assign({},obj1)
obj2.name = 'ls'
console.log(obj1.name) // 'zs'
方法二 展开符 {…obj1}
var obj1 = {
	name:'zs',
	age:16
}
var obj2 = {...obj1}
obj2.name = 'ls'
console.log(obj1.name) // 'zs'
展开符的使用

展开符可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。

  1. 在函数调用时使用
// 1.等价于apply
function myFunction(x, y, z) { }
var args = [0, 1, 2];
myFunction(...args);	// 相当于 myFunction.apply(null,args)

// 2.在 new 表达式中应用
var dateFields = [1970, 0, 1]; // 1970年1月1日
var d = new Date(...dateFields);
  1. 构造字面量数组时使用
//1. 浅拷贝
var arr = [1, 2, 3];
var arr2 = [...arr]; // 相当于var arr2 = [1, 2, 3]

//2. 连接数组
var arr1 = [0, 1, 2];
var arr2 = [3, 4, 5];
var arr3 = [...arr1, ...arr2]; //相当于var arr3 = arr1.concat(arr2);
  1. 构造字面量对象时使用

深拷贝

深拷贝,拷贝所有的属性值,以及属性地址指向的值的内存空间。

方法一 JSON.parse(JSON.stringify(obj1))

用JSON.stringify将对象转成JSON字符串,再用JSON.parse()把字符串解析成对象,生成新对象。

var obj1 = {
	name:'zs',
	age:20,
	major:{
		first: 'Math'
		}
}
var obj2 = JSON.parse(JSON.stringify(obj1))
obj2.major.first = 'English'
console.log(obj1.major.first) // 'Math'

使用JSON方法存在的局限性

  • 会忽略 undefined
  • 会忽略 symbol
  • 不能拷贝函数函数
  • 不能解决循环引用的对象

具体参考JS 基础知识点及常考面试题(二)

方法二 _.cloneDeep(obj1)

推荐使用lodash的cloneDeep方法

var obj1 = {
	name:'zs',
	age:20,
	major:{
		first: 'Math'
		}
}
var obj2 = _.cloneDeep(obj1)
obj2.major.first = 'English'
console.log(obj1.major.first) // 'Math'
方法三 浅拷贝+递归实现简易深拷贝
function deepClone(obj){
	// 2.对传入参数进行校验,要为object或function,同时不能是null
	function isObject(o){
		return (typeof o === 'object' || typeof o === 'function') && o != null
	}
	if (!isObject(obj)){
		throw new Error('非对象')
	}
	
	// 3.考虑数组的兼容
	let newObj = Array.isArray(obj)? [...obj]:{...obj}
	
	// 1.浅拷贝+递归,如果是嵌套的引用类型则递归,如果是简单类型则直接浅拷贝
	Reflect.ownKeys(newObj).forEach(key=>{
		newObj[key] = isObject(obj[key])? deepClone(obj[key]):obj[key]
	})
	return newObj
}

var obj1 = {
	name:'zs',
	age:20,
	major:{
		first: 'Math'
		}
}
var obj2 = deepClone(obj1)
obj2.major.first = 'English'
console.log(obj1.major.first) // 'Math'

更多解析参考面试题之如何实现一个深拷贝

语法笔记

Reflect.ownKeys(obj)返回一个由目标对象自身的属性键key组成的数组。即该方法可以获取obj对象的所有属性(包括Symbol)

参考
浅拷贝与深拷贝

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值