js 深拷贝 vs 浅拷贝
js的数据基本类型有
string, number, boolean, undefined, null
引用类型有
object, function
js的v8引擎主要由两部分组成
- 内存堆(Memory Heap) -- 分配地址的地方
- 执行栈(Call Stack) -- 执行代码的地方
基本数据类型存放在 栈 中,是直接按值存放的,可以直接访问。
基础类型的值是不可变的, 就算动态改变了其值,返回新的值,但它的原始值是不会变的
var a = '123'
a[0] = '4'
console.log(a) // 123
所以记住,基础类型数据的值是不可变的。
而且基础类型的比较,是值的比较,只要值相等就是相等
var a = 1
var b = 1
console.log(a === b) //true
引用类型(object/function)是放在 堆 中的。
变量其实是一个放在栈中的指针,指针指向堆内存中的地址。
var person1 = {a: 1}
var person2 = {a: 2}
var person3 = {a: 3}
引用类型是可以直接改变其值的
var a = {b: 1}
a['b'] = 2
console.log(a) //{b: 2}
引用类型的比较是引用的比较,也就是指针地址的比较
var a = {c: 1}
var b = {c: 1}
console.log(a == b) //false
console.log(a===b) //false
数据赋值区别
基本类型的赋值是两个独立互不影响的变量。
var a = 1
var b = a
a = 2
console.log(a) //2
console.log(b) //1
引用类型的赋值,实际上是传址,改变指针的指向。
也就是两个不同的栈指向相同的堆地址,变化会互相影响
var a = {}
var b = a
a.name = 1
console.log(a) // {name: 1}
console.log(b) // {name: 1}
console.log(a == b) //true
但是,以上这种赋值并不算浅复制,只能算是引用。
对于基本类型,浅复制就是对值的赋值,
对于引用类型,浅复制是对对象地址的赋值,并在堆中没有开辟新的地址。
而深复制会开辟新的地址,两个对象指向不同地址,互不影响。
这边我们只讲深复制,浅复制比较简单不做代码演示。
深拷贝
//方法一:有局限性,嵌套obj无法复制
var ary2 = ary1.concat();
//方法二:有局限性,会丢失function
var ary2 = JSON.parse(JSON.stringify(ary1));
//方法三, 有局限性,嵌套obj无法复制
var ary2 = [...ary1];
// 方法四, 有局限性,嵌套obj无法复制
var [...ary2] = ary1;
// 方法五,递归拷贝,推荐!!!
// 所有继承了 Object 的对象都会继承到 hasOwnProperty 方法,这个方法可以用来检测一个对象是否含有特定的自身属性;
// 和 in 运算符不同,该方法会忽略掉那些从原型链上继承到的属性。
function deepClone(obj) {
let copy = obj instanceof Array ? [] : {}
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
copy[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
}
return copy
}