深拷贝浅拷贝的原理
// 浅拷贝的方法
let arr = [1,2,3,4];
let newArr = arr;
- 浅拷贝的缺点
当你创建一个新的变量newArr直接复制已有变量的数据时,你改变原变量arr数据,新的变量newArr数据也会发生改变,最终两个的变量值是一样的
// 浅拷贝的方法
let arr = [1,2,3,4];
let newArr = arr;
arr[0] = 999;
console.log(arr,newArr) // 结果[1,2,3,999] [1,2,3,999];
-
深拷贝
- 深拷贝生成一个新的存储空间,将数据复制到这个新的存储空间中,从而改变原数据不会影响深拷贝后的数据
-
深拷贝的使用方法
-
扩展运算符
- 扩展运算就是,生成一个新的数据类型,相当于开辟一个新的指针,将原数据通过扩展运算符进行赋值
let arr = [1,2,3,4];
let newArr = [...arr];
arr[0] = 999;
// 改变原数据的值,不会影响深拷贝后的数据
console.log(arr,newArr) // 结果[1,2,3,999] [1,2,3,4];
- 缺点:不会改变深层次数据的指针,深层次数据的指针还是指向原数据,否则改变原数据的深层次深拷贝后的数据的深层次也会发生改变
let arr = [1,2,3,4,{name:'李四'}];
let newArr = [...arr];
arr[arr.length - 1].name = '张三';
console.log(arr,newArr) // 结果[1,2,3,4,{name:'张三'}],[1,2,3,4,{name:'张三'}]
let arr = [1,2,3,4,{name:'李四'}];
let newArr = json.parse(json.stringify(arr))
arr[arr.length - 1].name = '张三';
console.log(arr,newArr) // 结果[1,2,3,4,{name:'张三'}],[1,2,3,4,{name:'李四'}]
let arr = [1,2,3,4,{name:'李四'}];
let newArr = Object.assign([],arr)
arr[0] = 999
console.log(arr,newArr);
- 缺点:不会改变深层次数据的指针,深层次数据的指针还是指向原数据,否则改变原数据的深层次深拷贝后的数据的深层次也会发生改变
let arr = [1,2,3,4,{name:'李四'}];
let newArr = Object.assign([],arr)
arr[arr.length - 1].name = '张三';
console.log(arr,newArr) // 结果[1,2,3,4,{name:'张三'}],[1,2,3,4,{name:'张三'}]
var obj = { // 定义要进行深复制的对象
name: "张三",
age: 14,
tel: 110,
info: {
isSingle: true
}
}
// 定义深复制的函数
function deepClone(params) {
// 创建一个接受递归后数据的变量
var obj = {}
// 如果形参的数据不是Object的话return
if(!(params instanceof Object)) return
// 循环形参的数据
for(let key in params) {
// 判断循环出的数据是否为Object
if(params[key] instanceof Object) {
// 如果是Object拿之前的创建的变量接收一个函数的自我调用,将Object以实参传递给当前函数
obj[key] = deepClone(params[key])
// 循环出的数据不为Object
} else {
// 将数据直接赋值给生成的变量
obj[key] = params[key]
}
}
// 将接收的数据return出去
return obj
}
// 验证结论
var obj2 = deepClone(obj)
obj2.name = '李四'
obj2.info.isSingle = false
console.log(obj, obj2)
原型
- 以图参考
数据类型
基本数据类型:number、string、boolean、undefined、null,es6新增symbol , 值存在栈中
引用数据类型:Object、Array、function,值存在堆中
let arr = 1;
console.log(typeOf(arr)) // 结果Number
let arr2 = 'abc';
console.log(typeOf(arr2)) // 结果String
- 缺点:当数据为引用数据类型时,判断出结果就是字符串object
let arr = [1,231,4];
console.log(typeOf(arr)) // 结果object
let arr = [1,231,4];
console.log(arr instanceof Array); // 结果为true
- 缺点:当数据为基本数据类型时,判断出结果就是false
let num = 1;
let num2 = '1';
console.log(num instanceof Number); // 结果为false
console.log(num2 instanceof String); // 结果为false
- constructor:对引用数据类型和基本数据类型都有很好的判断,但是如果生成一个函数,把他的原型指向数组后者对象,那么他的判断结果就不一定是函数了
-
Object.prototype.toString.call():完美判断所有数据的类型,如果需要判断深层数据时,需要使用递归的方式
let arr = [1,2,3,4,{name:'李四'}];
let num = 1;
let str = '1';
let obj = {name:'张三'};
console.log(Object.prototype.toString.call(arr)); // 结果为 [object Array]
console.log(Object.prototype.toString.call(num)); // 结果为 [object Number]
console.log(Object.prototype.toString.call(str)); // 结果为 [object String]
console.log(Object.prototype.toString.call(obj)); // 结果为 [object Object]