浅拷贝与深拷贝
栈内存和堆内存
- 栈内存:简单数据类型 string,number,boolean,null,undefined
- 堆内存:复杂数据类型 object,array....
注意:
- 浅拷贝就是将引用数据类型 在栈内存中的引用地址拷贝一份 指向的还是堆空间的旧数据数据
- 深拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象
1.浅拷贝
// 浅拷贝
let arr1 = ["北京", "上海", "广州",["白云区","黄埔区"]]
// arr1赋值给arr2
// *****这里只是将数组的引用的地址拷贝了一份赋值给了arr2
let arr2 = arr1
arr2[0] = "beijing"
console.log("arr2", arr2)
console.log("arr1", arr1)
注意:
因为两份地址指向的是同一数据,所以当arr2改变数组的内容时,arr1打印的结果也会发生改变。
2.深拷贝
利用for in循环 进行深拷贝
// 深拷贝
let arr1 = ["北京", "上海", "广州",{uname:"小明",age:21}]
let arr2 = []
// 先通过for in 循环数组 能够拿到数组中的每一项
// 注意:因为 for in 循环 既可以循环数组也可以循环兑对象
for (k in arr1) {
// 由于数据结构是数组嵌套对象 所以需要进行对数据类型进行判断
if (arr1[k] instanceof Array) {
//如果数组里的数据还有数组就在数组里定义一个空数组
arr2[k] = []
// 继续进行二次循环将数组的值循环赋值给空数组
for (var m in arr1[k]) {
arr2[k][m] = arr1[k][m]
}
// 如果是对象的话同理 进行循环
} else if (arr1[k] instanceof Object) {
//对象
arr2[k] = {}
for (n in arr1[k]) {
arr2[k][n] = arr1[k][n]
}
} else {
//这里是简单数据类型 可以直接赋值
arr2[k] = arr1[k]
}
}
// 打印结果
arr2[3].uname = "修改测试"
// 同打印两个数据进行比较
console.log("arr2", arr2,"arr1", arr1)
注意
因为深拷贝实在堆内存中开辟了新的空间,把原数据拷贝了这个新开辟的空间中,所以两个数组互不干涉,新数据修改对原数据没有影响。
利用递归实现深拷贝
递归就是自己调用自己
var obj1 = {
uname: "小明",
age: 21,
school: {
name: "清华大学",
address: "海淀",
subSchool: { name: "清华美院", address: "五道口" }
},
hobby: ["学习", "跑步", "吃饭"]
}
//调用
var obj2 = {}
deepCopy(obj2, obj1)
//定义
function deepCopy(obj2, obj1) {
for (k in obj1) {
if (obj1[k] instanceof Array) {
obj2[k] = []
deepCopy(obj2[k], obj1[k])
} else if (obj1[k] instanceof Object) {
obj2[k] = {}
deepCopy(obj2[k], obj1[k])
} else {
//简单数据类型
obj2[k] = obj1[k]
}
}
}
obj2.school.name = "qinghuadaxue";
console.log(obj2,obj1);
利用JSON.parse(JOSN.stringify()) 实现暴力深拷贝
先利用JSON.stringify 将对象转为JOSN字符串进行拷贝,在l利用JSON.parse()方法转换为对象
var obj1 = {
name: "小明",
age: 21,
height: 170,
school: {
name: "清华大学",
addres: "北京"
}
}
var obj2 = JSON.parse(JSON.stringify(obj1))
obj2.school.name = "清华美术学院"
// 可以发现修改了obj2,不影响obj1
console.log("obj5", obj2);
console.log("obj3", obj1);
闭包
闭包就是 能够读取其他函数内部变量的函数
函数嵌套函数 当内部函数访问外部函数内部的变量时,就会形成闭包
案例
点击元素改打印元素中的内容
<body>
<ul>
<li>八戒</li>
<li>悟空</li>
<li>唐僧</li>
<li>沙僧</li>
</ul>
</body>
<script>
var list = document.querySelectorAll("li")
// console.log(list)
/*利用闭包,实现列表内容的点击获取*/
for (var i = 0; i < list.length; i++) {
(function (i) {
list[i].onclick = function () {
console.log(list[i].innerHTML)
}
})(i)
}
</script>
var,const,let关键字
-
暂时性死区
使用ES6的变量声明方法(
let
,const
,class
…)声明的变量,不可在声明前使用访问,否则会进行显式报错。ES6变量声明前的代码区域,称为 “暂时性死区”let x=1; let foo=function(){ //暂时性死区 console.log(x) let x=2; } foo()