一、数据类型
JavaScript 中存在两大数据类型
- 基本类型
- 引用类型
基本类型数据存储在栈内存中 储存的是值本身
引用类型数据保存在堆内存中 引用类型的变量是一个指向内存中实际对象的地址
二、浅拷贝
浅拷贝 指创建一个新的数据 这个数据有着初始数据属性值的一份精确拷贝
如果属性是基本类型 拷贝的就是基本类型的值 如果类型是引用类型 则拷贝内存地址
注意点:浅拷贝只拷贝对象的一层属性,如果拷贝是内存地址 两者修改会有影响
简单实现浅拷贝
// 原始:遍历
function shallowClone(obj) {
const newObj = {};
for(let key in obj) {
if(obj.hasOwnProperty(key)){
newObj[key] = obj[key];
}
}
return newObj;
}
在 JavaScript 中 还可以使用以下方法实现浅拷贝
- Object.assign
- Array.concat
- 扩展运算符
Object.assign
let obj = {
name: "赵小童",
age: 22,
color: "green",
}
let NewObj = Object.assign({}, obj)
Array.cancat
const arr = [1, 2, 3, 4, 5, 6]
let newArr = arr.concat([])
扩展运算符
let obj = {
name: "赵小童",
age: 22,
color: "green",
}
let NewObj = { ...obj }
obj.name = "蒋敦豪"
console.log(obj)
console.log(NewObj)
// ===========================================
let arr = [1, 2, 3, 4, 5, 6]
let newArr = [...arr]
console.log(arr)
console.log(newArr)
console.log(arr === newArr)
三、深拷贝
深拷贝会开辟一个新的栈 两个对象属性完全相同 但是对应两个不同的地址 修改一个对象的属性 不会改变另一个对象的属性
深拷贝就是拷贝对象的多层属性 如果对象里面还有对象 会继续拷贝
具体实现方法
- 使用递归函数遍历
- 使用lodash库
- JSON系列化
循环递归
function deepClone(obj, hash = new WeakMap()) {
if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
if (obj instanceof Date) return new Date(obj);
if (obj instanceof RegExp) return new RegExp(obj);
// 可能是对象或者普通的值 如果是函数的话是不需要深拷贝
if (typeof obj !== "object") return obj;
// 是对象的话就要进行深拷贝
if (hash.get(obj)) return hash.get(obj);
let cloneObj = new obj.constructor();
// 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
hash.set(obj, cloneObj);
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 实现一个递归拷贝
cloneObj[key] = deepClone(obj[key], hash);
}
}
return cloneObj;
}
lodash库
// 1、先引入lodash库
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.js"></script>
let obj = {
name: "王一珩",
age: 18,
clothes: "东北大花袄",
car: {
carName: "大黄蜂",
carPrice: 9.99,
},
}
// 2、使用 _cloneDeep方法
let newObj = _.cloneDeep(obj)
consolr.log(newObj)
JSON序列化
const obj2=JSON.parse(JSON.stringify(obj1));
// ================================================
let str = JSON.stringify(obj)
let newObj = JSON.parse(str)
obj.car.carName = "蓝色三轮车"
console.log(obj)
console.log(newObj)
这种方法会有弊端 会忽略undefined 、symbol 和 函数
const obj = {
name: 'A',
name1: undefined,
name3: function() {},
name4: Symbol('A')
}
const obj2 = JSON.parse(JSON.stringify(obj));
console.log(obj2); // {name: "A"}
小结:
前提为拷贝类型为引用类型的情况下:
浅拷贝是拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
深拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址