网站怎么做必须交钱吗,小蘑菇网站建设软件,怎么查网站的备案号,打开网站建设中是什么意思详解js中的浅拷贝与深拷贝 1、前言1.1 栈#xff08;stack#xff09;和堆#xff08;heap#xff09;1.2 基本数据类型和引用数据类型1.2.1 概念1.2.2 区别1.2.3 基本类型赋值方式1.2.4 引用类型赋值方式 2、浅拷贝2.1 概念2.2 常见的浅拷贝方法2.2.1 Object.assign()2.2.… 详解js中的浅拷贝与深拷贝 1、前言1.1 栈stack和堆heap1.2 基本数据类型和引用数据类型1.2.1 概念1.2.2 区别1.2.3 基本类型赋值方式1.2.4 引用类型赋值方式 2、浅拷贝2.1 概念2.2 常见的浅拷贝方法2.2.1 Object.assign()2.2.2 扩展运算符(...)2.2.3 Array.concat()2.2.4 Array.slice() 3、深拷贝3.1 概念3.2 常见的深拷贝方法3.2.1 JSON.parse(JSON.stringify(obj))3.2.2 递归3.2.2 函数库lodash 4、总结5、应用场景 1、前言
1.1 栈stack和堆heap
栈(stack):由操作系统自动分配释放 存放函数的参数值局部变量的值等。其操作方式类似于数据结构中的栈堆(heap)一般由程序员分配释放 若程序员不释放程序结束时可能由OS回收分配方式倒是类似于链表
1.2 基本数据类型和引用数据类型
1.2.1 概念
基本数据类型Number、String、Boolean、Null、 Undefined、SymbolES6引用数据类型Object、Array、Function、Date、RegExp、Map、Set等。
1.2.2 区别 两者区别 内存地址分配: 1基本数据类型:将值存储在栈中 ,栈中存放的是对应的值 2引用数据类型:将对应的值存储在堆中,栈中存放的是指向堆内存的地址赋值变量 1基本数据类型是生成相同的值两个对象对应不同的地址 2引用数据类型是将保存对象的内存地址赋值给另一个变量。也就是两个变量指向堆内存中同一个对象 let a 10;let b a; // 赋值操作b 100;console.log(a); // 10总结 a是基本类型存储在栈中把a赋值给b虽然两个变量的值相等但是两个变量保存了两个不同的内存地址。
1.2.3 基本类型赋值方式 1.2.4 引用类型赋值方式 let obj1 {}let obj2 objobj2.name 李四console.log(obj.name) // 李四理解obj1是引用类型,将数据存放在堆内存中,而栈中存放的是内存地址.在obj1赋值给obj2实际是将obj1的引用地址复制了一份给了obj2实际上他们共同指向了同一个堆内存对象所以更改obj2会对obj1产生影响 2、浅拷贝
2.1 概念 会在栈中开辟另一块空间并将被拷贝对象的栈内存数据完全拷贝到该块空间中即基本数据类型的值会被完全拷贝而引用类型的值则是拷贝了“指向堆内存的地址”。 2.2 常见的浅拷贝方法
Object.assign()扩展运算符(…)Array.concat()Array.slice()
2.2.1 Object.assign()
object.assign 是 ES6 中 object 的一个方法该方法可以用于JS 对象的合并等多个用途其中一个用途就是可以进行浅拷贝。 object.assign 的语法为Object.assign(target, …sources) var obj { x: 1, y: 2,z: { num: 10 }
}
var newObj {}
Object.assign(newObj, obj)
newObj.y 3
console.log(obj)
console.log(newObj) 运行结果如下
注意
Object.assign()不会拷贝对象的继承属性Object.assign()不会拷贝对象的不可枚举的属性Object.assign()可以拷贝 Symbol 类型的属性。
2.2.2 扩展运算符(…) 扩展运算符的语法为let cloneObj { …obj }; /* 对象的拷贝 */
const obj {a: 1,b: {c: 1}
}
const obj2 {...obj
}
obj.a 2console.log(obj)
console.log(obj2); obj.b.c 2console.log(obj)
console.log(obj2); /* 数组的拷贝 */
let arr [1, 2, 3];
let newArr [...arr]; // 跟arr.slice()是一样的效果运行结果如下
注意扩展运算符 和 object.assign 有同样的缺陷也就是实现的浅拷贝的功能差不多但是如果属性都是基本类型的值使用扩展运算符进行浅拷贝会更加方便。
2.2.3 Array.concat()
var obj1 [Chinese, { name: zs }, French]
var obj2 obj1.concat()
obj2[1].name ls
obj2[2] China
console.log(obj1, obj2);运行结果如下 注意数组的 concat 方法其实也是浅拷贝所以连接一个含有引用类型的数组时需要注意修改原数组中的元素的属性因为它会影响拷贝之后连接的数组。不过 concat 只能用于数组的浅拷贝使用场景比较局限。
2.2.4 Array.slice() slice 的语法为arr.slice(begin, end); var arr [2, 4, 6, { y: 10 }]
var newArr arr.slice()
newArr[0] 10
newArr[3].x 20
newArr[3].y 30
console.log(arr)
console.log(newArr)运行结果如下 注意slice 方法也比较有局限性因为它仅仅针对数组类型。slice 方法会返回一个新的数组对象这一对象由该方法的前两个参数来决定原数组截取的开始和结束位置是不会影响和改变原始数组的。但是数组元素是引用类型的话也会影响到原始数组。
3、深拷贝
3.1 概念 深拷贝是拷贝多层每一级别的数据都会拷贝出来。 3.2 常见的深拷贝方法
JSON.parse(JSON.stringify(obj))递归方法函数库 lodash
3.2.1 JSON.parse(JSON.stringify(obj)) 原理:用 JSON.stringify 将对象转成 JSON 字符串再用 JSON.parse() 把字符串解析成对象。一去一来新的对象就产生了而且对象会开辟新的栈实现深拷贝。 let a {name: 张三, age: 19, like: [打篮球, 唱歌, 跳舞]}
let b JSON.parse(JSON.stringify(a))
a.name 李四
a.like[0] 睡觉
console.log(a)
console.log(b) 运行结果如下 但是JSON.stringify并不是那么完美的它也有局限性。
拷贝的对象的值中如果有函数、undefined、symbol 这几种类型经过 JSON.stringify 序列化之后的字符串中这个键值对会消失拷贝 Date 引用类型会变成字符串无法拷贝不可枚举的属性无法拷贝对象的原型链拷贝 RegExp 引用类型会变成空对象对象中含有 NaN、Infinity 以及 -InfinityJSON 序列化的结果会变成 null无法拷贝对象的循环应用即对象成环 (obj[key] obj)。
let obj {func: function () { alert(1) },obj: { a: 1 },arr: [1, 2, 3],und: undefined,reg: /123/,date: new Date(0),NaN: NaN,infinity: Infinity,sym: Symbol(1)
}Object.defineProperty(obj, innumerable, {enumerable: false,value: innumerable
});console.log(obj, obj); // { NaN: NaN , arr: (3) [1, 2, 3] ,date: Thu Jan 01 1970 08:00:00 GMT0800 (中国标准时间) {}, func: ƒ(), infinity: Infinity , obj: { a: 1 } , reg: /123/, sym: Symbol(1), und: undefined, innumerable: innumerable }const str JSON.stringify(obj);const obj1 JSON.parse(str);console.log(obj1, obj1); // { NaN: null, arr: (3) [1, 2, 3], date: 1970-01-01T00:00:00.000Z, infinity: null, obj: {a: 1}, reg: {} }3.2.2 递归 function deepCopyTwo(obj) {let objClone Array.isArray(obj) ? [] : {};if (obj typeof obj object) {for (const key in obj) {//判断obj子元素是否为对象如果是递归复制if (obj[key] typeof obj[key] object) {objClone[key] deepCopyTwo(obj[key]);} else {//如果不是简单复制objClone[key] obj[key];}}} return objClone;}3.2.2 函数库lodash lodash是一个著名的javascript原生库不需要引入其他第三方依赖。是一个意在提高开发者效率,提高JS原生方法性能的JS库。简单的说就是很多方法lodash已经帮你写好了直接调用就行不用自己费尽心思去写了而且可以统一方法的一致性。Lodash使用了一个简单的_ 符号就像Jquery的 $ 一样十分简洁。lodash函数库提供 _.cloneDeep用来做深拷贝。 let _ require(lodash);let obj {a:1,b:{f:{g:1}},c:[1,2,3]};let newObj _cloneDeep(obj);console.log(obj.b.f newObj.b.f); //true4、总结
浅拷贝就是只拷贝基础数据类型的数据并且数据只有单一的一层而深拷贝用于拷贝具有复杂的数据类型的数据
5、应用场景
浅拷贝主要用于你需要拷贝的对象的数据结构只有基础数据类型并且你不想改变原数据类型或者需要对比操作前后的数据。深拷贝主要用于你想操作该数据但是又不想影响到原数据的时候就可以进行深拷贝。