1.浅拷贝 深拷贝
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
// 浅拷贝 --- 当我们想要把一个对象赋值一份的时候使用
/*
var obj = {
name: '卡布达',
sid: 1,
zhuren: {
name: '小让'
}
};
obj.gender = '男'
var obj2 = {};
for (var key in obj) {
if (obj.hasOwnProperty(key)) {
obj2[key] = obj[key];
}
}
obj2.zhuren.name = '小百合';
console.log(obj); //此时obj里的内容和obj2的结果是一样的
console.log(obj2); // 修改obj2会将obj的内容也改变
*/
// 上面就是浅拷贝的过程(都是值类型的时候 没问题)
// 如果对象里面有引用类型, 也会把这个引用类型再复制一份
// 深拷贝 即使对象的属性是引用类型,也会把这个引用类型再复制一份
var obj = {
name: '卡布达',
sid: 1,
zhuren: {
name: '小让',
baba: {
name: '高院寺',
}
}
}
// for (var key in obj) {
// console.log(key);
// }
// // obj.name obj[key]
// // obj.zhuren.name obj[k][key]
// obj.age=78;
// console.log(obj);
// console.log(obj.hasOwnProperty('age'));
var obj2 = {}
for (var key in obj) {
if (obj.hasOwnProperty(key)) {//复制时只复制obj中原有的属性而不复制原型对象
// 如何判断这个值是不是引用类型 typeof==='object'
if (typeof obj[key] === 'object') {
obj2[key] = {};
for (var k in obj[key]) {
console.log(k);
// 仍然要判断当前这个对象的属性的值是不是引用类型
if (typeof obj[key][k] === 'object') {
obj2[key][k] = {};
for (var kk in obj[key][k]) {
obj2[key][k][kk] = obj[key][k][kk]
}
} else {
obj2[key][k] = obj[key][k];
}
}
} else {
obj2[key] = obj[key];
}
}
}
obj2.zhuren.baba.name='李白';
console.log(obj2);
console.log(obj);//obj2 中的值被改变后obj中的值不会被影响
// 通过递归实现森拷 贝
var obj = {
name: '坤坤',
age: 24,
aihao: ['篮球', '跳', '跳', 'rap'],
zuopin: {
name: '姬霓太美',
hobby: {
name: ' 发律师函',
team: {
name: '坤哥律师事务所'
}
}
}
}
// 通过递归需要两个参数 一个原来的对象 一个是复制之后新的对象
function deepCopy(oldObj,newObj){
// 把旧的对象每一个键值对都复制到新的对象中
for(let key in oldObj){
if(oldObj.hasOwnProperty(key)){
// 判断key对应的值是不是引用类型
if(typeof oldObj[key]==='object'){
// 创建一个新的对象 把 key对应的值(对象)里面每一个键值对赋值一份
// 引用类型中有一种比较特殊 数组 如果是数组的话 就应该改一个数组 如果不是数组 给 对象
newObj[key]=oldObj[key] instanceof Array?[]:{}
deepCopy(oldObj[key],newObj[key]);
}else{
newObj[key]=oldObj[key];
}
}
}
}
var obj2={}
deepCopy(obj,obj2);
obj2.zuopin.hobby.name='唱跳rap篮球'; //obj2中的内容改变后,obj中的内容不会被改变
console.log(obj);
console.log(obj2);
</script>
</html>
2.递归和for的执行效率
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
// 不到万不得已 千万别使用递归
// 首先 递归的执行效率要比循环慢
// 因为递归函数可以会创建多个局部作用域,要执行函数的代码
// 这部分在递归函数创建的作用域可以会非常多 在函数执行结束之后,又会回收
// for 这个函数调用的时候 只生成一个局部作用域
// function add(n){
// var sum=0;
// for(var i=0;i<n;i++){
// sum+=i;
// }
// return sum;
// }
// console.log(add(10));
// 递归 会生成n个局部作用域
function fn(n) {
if (n === 1) return 1;
return n + fn(n - 1);
}
fn(10);
console.log(fn(10));
</script>
</html>
3.闭包
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
// 什么是闭包?一个局部患上访问上级作用域里面的数据,就会形成闭包
// 可以拓展局部函数的作用范围
// 闭包的正常使用
// 把内部函数返回各样外部调用
function fn(){
var x=10;
function fn1(){
console.log(x);
}
return fn1;
}
var fn5=fn();
console.log(fn5);
fn5()
</script>
</html>
4.使用闭包实现数据私有化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
/*
去银行存钱,都是小姐姐--存钱就是数据私有化的过程
需要找一个地方存钱--安全性
提供一个窗口(人工,ATM)进行数据的操作(钱的数量的变化)
*/
function cun(){
var money =0;
function xiaojiejie(n){
money+=n;
console.log(money);
}
return xiaojiejie;
}
var xiaojiejie=cun()
xiaojiejie(10000);
// 实现 存钱 取钱 查余额
function ICBC(){
var money=0;
return{
cunqian:function(n){
money+=n;
},
quqian:function(n){
if(money>=n){
money-=n;
}else{
alert('你TM有多少余额自己没点B数吗?')
}
},
chayue:function(){
console.log(money);
}
}
}
var xiaojiejie=ICBC()
xiaojiejie.cunqian(100)
xiaojiejie.quqian(200)
xiaojiejie.chayue()
</script>
</html>
5.闭包的使用技巧
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
.box {
width: 100px;
height: 100px;
background-color: tomato;
float: left;
margin-right: 10px;
}
</style>
</head>
<body>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
<div class="box"></div>
</body>
<script>
var boxs = document.querySelectorAll(".box");
// for(var i =0;i<boxs.length;i++){
// boxs[i].onclick=function(){
// console.log(i);//每次输出的值都为4
// }
// }
// 解决方法
// 方法一
// for(let i=0;i<boxs.length;i++){
// boxs[i].onclick=function(){
// console.log(i);//点击相应的元素,输出对应的下标
// }
// }
// 方法2:在点击事件外 存起来
// for(var i=0;i<boxs.length;i++){
// boxs[i].index=i;
// boxs[i].onclick=function(){
// console.log(this.index);
// }
// }
// 方法3 使用闭包
// function fn(i){
// boxs[i].onclick=function(){
// console.log(i);
// };
// }
// for(var i=0;i<boxs.length;i++){
// fn(i)
// }
for (var i = 0; i < boxs.length; i++) {
(function (a) {
console.log(a);
boxs[a].onclick = function () {
console.log(a);
}
})(i);
// (函数)(调用函数(参数看看有没有))
}
</script>
</html>
6.闭包的缺点
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body></body>
<script>
// 正常情况下 函数里面的数据在函数执行完毕之后会回收的
function fn(){
var a=10;
console.log(++a);
}
fn();
fn();
fn();
fn();//由于回收每次都初始化
// 如果是在闭包产生的情况下 函数内部的数据就无法正常的回收了
function fn(){
var x=10;
function f2(){
console.log(++x);
}
return f2;
}
var f2=fn();
f2();
f2();
f2();
// f2();
// 闭包会导致数据活跃在内存里面 无法被回收
// 闭包越多,内存就会越来越少 对程序的执行不友好
// 闭包不要滥用,在确实需要的时候才使用
// 难道就灭有办法收拾闭包导致活跃的数据吗?
// 垃圾回收机制 ---保洁 会在需要的时候清理内存的垃圾
// 垃圾回收机制之一 引用计数---当引用计数为0的时候,就会把垃圾回收
// 将闭包的函数设置为null
f2=null;
f2();
</script>
</html>