基本数据类型: String, Boolean, Number, Undefiend, null
引用数据类型:Object, Array, Function, Date, RegExp
基本数据类型和引用类型的区别:
1、保存的位置不同:
-
基本数据类型保存在栈内存中
例如 let a = 1
当 let b = a时,栈内存会开辟一个新内存
所以 这时候a和b时完全独立,互不影响的 引用数据类型,名存在栈内存中,值存在堆内存中,但是栈内存会提供一个地址指向堆内存中的值
例如:
let a = [0,1,2,3,4]
let b = a
a[0] = 1
当a[0]=1进行数组修改时,a和b指向同一个地址,所以b也会受到影响,这就是所谓的浅拷贝
如果时深拷贝的话,就是在堆内存中也开辟了一个新的内存放b的值,那就达到深拷贝的效果了
为什么基本类型保存在栈中,而引用数据类型保存在堆中?
1、堆比栈大,栈的速度比堆块
2、基本数据类型比较稳定,而且相对来说占用的内存小
3、引用数据类型大小是动态的,而且是无限的,引用值的大小会改变,不能把它放在栈中,否则会降低变量查找的速度,因此放在变量栈空间的值是该对象存储在堆中的地址,地址的大小固定,所以把它存储在栈中对变量性能无任何负面影响
4、堆内存是无序存储,可以根据引用直接获取
Array.prototype.slice(), Array.prototype.concat(), ...(ES6的解构), Object.assign()都是一层拷贝,不算是深拷贝,二级属性不能拷贝出来,第一级的属性确实深拷贝了,拥有了独立的内存,但更深的属性却仍然共用地址。
深拷贝的实现:
1、当对象只有一级属性的时候可以用以下方法进行深拷贝
1) Object.assign()
let obj1 = {name: "victor"}
let obj2 = Object.assign({},obj1)
obj2.name = "john"
console.log('obj1:', obj1) // obj1 { name: 'victor' }
console.log('obj2:', obj2) // obj2 { name: 'john' }
2)Array.prototype.concat()
3)Array.prototype.slice()
4)ES6 解构
let obj1 = {name: "victor"}
let obj2 = {...obj1}
obj2.name = "john"
console.log('obj1:', obj1) // obj1 { name: 'victor' }
console.log('obj2:', obj2) // obj2 { name: 'john' }
2、 递归
function deepCopy(obj1){
let obj2 = Array.isArray(obj1)? []:{}
if(obj1 && typeof obj1 === "object"){
for(let i in obj1){
if(obj1[i] && typeof obj[i] === "object"){
obj2[i] = deepCopy(obj1[i])
}else{
obj2[i] = obj1[i]
}
}
}
}
return obj2
}
3、JSON.stringify() JSON.parse()结合使用
let a = {a:{b:1},c:1}
let b = JSON.parse(JSON.stringify(a))
b.a.b = 2
console.log(a)
console.log(b)
let obj1 = {
fun:function(){
alert(123);
}
}
let obj2 = JSON.parse(JSON.stringify(obj1));
console.log(typeof obj1.fun); // function
console.log(typeof obj2.fun); // undefined
缺陷 它会抛弃对象的constructor,深拷贝后,不管这个对象原来的构造函数是什么,在深拷贝之后都会变成Object,这种方法能正确处理的对象只有 Number,String,Boolean,Array,扁平对象,也就是说,只有能转成JSON格式的对象才可以这样用,像function就没办法转成JSON
4、jquery提供的$.extend()可以用来做深拷贝
var $ = require('jquery');
var obj1 = {
a: 1,
b: {
f: {
g: 1
}
},
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f); // false
5、lodash提供的 cloneDeep的方法
const _ = require('lodash');
// 官方例子
var objects = [{ 'a': 1 }, { 'b': 2 }];
var deep = _.cloneDeep(objects);
console.log(deep[0] === objects[0]);
// => false