js中数据类型分为简单数据类型(Undefined、Null、Boolean、String、Number)和复杂数据类型(Object),基本数据类型按值访问,复杂数据类型按引用访问。变量的值也就分为基本类型值和引用类型值。基本类型值就是简单的数据段,引用类型值则是由多个值构成的对象。
1、赋值
- 基本类型值在内存中占用固定大小,因为被保存在栈内存里。给新变量赋值原变量的基本类值时,会创建一个新的副本,然后把这个值复制到给新变量分配的位置上。
- 引用类型值保存在堆内存中(动态分配空间),js不允许直接访问堆内存中的位置,因此在复制操作对象时,实际操作的是对象的引用而不是实际的对象,引用指针也保存在栈内存里。给新变量赋值原变量的引用类值时,同样会创建一个新的副本,然后把原变量的引用复制到这个新变量上。复制的其实是这个引用指针而不是对象本身,最终两个变量会指向同一个对象。
2、深拷贝和浅拷贝只针对复杂数据类型Object。
3、浅拷贝:可以理解为在开辟的新的内存空间中,存放复制了原对象属性中基本类型值和引用类型值的引用。
(补图...)
- 实现浅拷贝的方式:
// 1、for in 循环第一层
funtcion shallowCopy (obj) {
let objClone = Array.isArray(obj) ? [] : {}
for (let i in obj) {
objClone[i] = obj[i]
}
return objClone
}
// 2、es6 Object.assign合并对象
obj = {
name: 'lily',
hobbies: ['sing', 'run']
}
let obj2 = Object.assign({}, obj)
obj.name = 'bob' // 第一层是基本类型,不会共享
console.log(obj) // {name: "bob", hobbies: ['sing', 'run']}
console.log(obj2) // {name: "lily", hobbies: ['sing', 'run']}
obj2.hobbies.push('football') // 第一层是引用类型,会被共享改变
console.log(obj) // {name: "bob", hobbies: ['sing', 'run', 'football]}
console.log(obj2) // {name: "lily", hobbies: ['sing', 'run', 'football]}
// 3、slice\concat等方法
// 4、es6 数组展开运算符...
let arr = [1,2,[3,4]]
let arr2 = [...arr]
arr[0] = 0
console.log(arr) // [0,2,[3,4]]
console.log(arr2) // [1,2,[3,4]]
arr2[2].push(5)
console.log(arr) // [0,2,[3,4,5]]
console.log(arr2) // [1,2,[3,4,5]]
4、深拷贝:从堆内存中开辟一个新的区域存放新对象,新对象跟原对象不共享内存,修改新对象不会改到原对象。
- 实现深拷贝的方式:
// 1、for in 递归循环复制
function deepClone (obj) {
let objClone = Array.isArray(obj) ? [] : {}
if (obj && typeof obj == 'object') {
for (let i in obj) { // for in循环实例自身和原型的属性
if (obj.hasOwnProperty(i)) { // 判断是自身的属性
if (obj[i] && typeof obj[i] == 'object') {
objClone[i] = deepClone(obj[i])
} else {
objClone[i] = obj[i]
}
}
}
}
return objClone
}
// 2、JSON.parse(JSON.stringify(obj)):
// 只适用于一般的对象和数组深拷贝,遇到function、RegExp、Date等就不准确了(具体情况具体分析)。
let obj = {
name: 'lily',
hobbies: ['sing', 'run']
}
let obj2 = JSON.parse(JSON.stringify(obj))
obj.name = 'bob'
console.log(obj) // {name: "bob", hobbies: ['sing', 'run']}
console.log(obj2) // {name: "lily", hobbies: ['sing', 'run']}
obj2.hobbies.push('football')
console.log(obj) // {name: "bob", hobbies: ['sing', 'run']}
console.log(obj2) // {name: "lily", hobbies: ['sing', 'run', 'football']}