数据类型
- 基本数据类型:string,Number,Boolean,Null,Undefined,Symbol
- 特点:直接存储在栈(stack)中
- 引用数据类型:Array,Obeject
- 特点:存储的是该对象在栈中的引用,真实数据存放在堆内存里
深拷贝 && 浅拷贝
深拷贝和浅拷贝只是针对于引用数据类型的,浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象共享一个内存。深拷贝恰恰相反。
赋值 && 浅拷贝
对象赋值是把该对象存储在栈中的地址赋给一个新变量,而不是堆中的数据,也就是说,无论哪一个对象改变,另外一个对象会跟着改变
var obj1= {
"name": "zhangsan",
"age":"18",
"language":[1,[2,3],[4,5]],
}
var obj2 = obj1
obj2.name = lisi"
obj2.language[1] = ["二", "三"]
console.log("obj1", obj1)
console.log("obj2", obj2)
结果是:
{
"name": "lisi",
"age":"18",
"language":[1,["二", "三"],[4,5]],
}
{
"name": "lisi",
"age":"18",
"language":[1,["二", "三"],[4,5]],
}
浅拷贝会创建一个全新的对象,这个对象有原对象一份精确的拷贝。其中,如果属性是基本类型,则拷贝的就是基本类型的值,如果是引用类型,拷贝的就是内存地址。默认拷贝构造函数只是对对象的浅拷贝。
一个亲拷贝的实现
function shallowCopy(src){
var dis = {}
for(var prop in src){
if(src.hasOwnProperty(prop)){
dis[prop] = src[prop]
}
}
return dist
}
如果对对象 obj1 通过上边的方法进行浅拷贝出来一个obj3,然后对 Obj3 的 name 和 language 进行修改,最终结果是 obj1 的 name 未发生改变,而 language 值方发生了改变。看来,obj3.language[1] = [“二”, “三”] 的操作相应地址指向了内存中的数据[“二”, “三”],自然 obj1 中的相应地址也指向了它。
实现浅拷贝的 API
Object.assign()
//当 Object 只有一层时,是深拷贝Array.prototype.concat()
Array.prototype.slice()
深拷贝实现方式
JOSN.parse(JSON.Stringfy())
:这种方法虽然可以实现数组或者对象的深拷贝,但不能处理函数- 手写递归方式
递归方法实现深拷贝的原理:便利对象、数组,值到里边都是基本数据类型,然后再去fu’z,就是深拷贝
// 定义检测数据类型的功能函数
function checkedType(target){
return Object.prototype.toString.call(target).slice(8, -1)
}
// 实现深拷贝
function clone(target){
// 判断拷贝的数据类型
// 初始化变量 result 成为最终克隆的数据
let result, targetType = checkedType(target)
if(targetType === Object){
return result = {}
} else if(targetType === Array) {
return result = []
} else {
return target
}
// 遍历目标数据
for(let i in target) {
let value = target[i]
if(checkedType(value) === "Object" || checkedType(value) === "Array") {
return result[i] = clone(value)
} else {
result[i] = value
}
}
return result
}
- 函数库loadash
该函数库有提供_.cloneDeep
做深拷贝
var _ = require('lodash')
var obj1 = {
a:1,
b:{f:{g:1}},
c:[1,2,3]
}
var obj2 = _.cloneDeep(obj1)
console.log(obj1.b.f === obj2.b.f) //false