【JavaScript】深浅拷贝及闭包详解

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

💻 【JavaScript】深浅拷贝及闭包详解 🏠专栏JavaScript
👀个人主页繁星学编程🍁
🧑个人简介一个不断提高自我的平凡人🚀
🔊分享方向目前主攻前端其他知识也会阶段性分享🍀
👊格言☀️没有走不通的路只有不敢走的人☀️
👉让我们一起进步一起成为更好的自己🎁

文章目录

【JavaScript】深浅拷贝及闭包详解

一. 深浅拷贝

(1) 赋值

赋值把一个数据结构的地址复制一份给另一个变量

(2) 浅拷贝

浅拷贝原先是什么数据结构创建一个一模一样的数据结构

依次遍历原始数据结构把每一个数据复制一份放到新的数据结构内只能拷贝一次数据结构
原始数据结构中的key

  • 存储的是基本数据类型可以拷贝
  • 存储的是引用数据类型无法拷贝
const obj1 = { name: 'zs', age: 18, info: { sex: "男" } }
const obj2 = {}
for (let k in obj1) {
    obj2[k] = obj1[k];
}
console.log(obj1, obj2); // {name: 'zs', age: 18, info: {…}} {name: 'zs', age: 18, info: {…}}
obj1.name = "ls";
console.log(obj1, obj2); // {name: 'ls', age: 18, info: {…}} {name: 'zs', age: 18, info: {…}}
obj1.info.sex = "女";
console.log(obj1, obj2); // 两个sex都改为女

Object.assign

语法Object.assign(新对象,原始对象)

返回值把原始对象内的数据浅拷贝一份放入到新对象中

const obj1 = { name: 'zs', age: 18, info: { sex: "男" } }
const obj2 = Object.assign({}, obj1);
console.log(obj1, obj2); // {name: 'zs', age: 18, info: {…}} {name: 'zs', age: 18, info: {…}}
obj1.name = "ls";
console.log(obj1, obj2); // {name: 'ls', age: 18, info: {…}} {name: 'zs', age: 18, info: {…}}

(3) 深拷贝

深拷贝不管多少层数据结构都百分百复制一份变成两个一模一样但是毫不相干的数据结构

方式一递归

const obj1 = { name: 'zs', age: 18, info: { sex: "男" } }
function deepClone(origin, target) {
    for (let k in origin) {
        if (origin[k] instanceof Object) {
            target[k] = {};
            deepClone(origin[k], target[k])
        } else if (origin[k] instanceof Array) {
            target[k] = [];
            deepClone(origin[k], target[k])
        } else {
            target[k] = origin[k];
        }
    }
    return target;
}
const obj2 = deepClone(obj1, {});
console.log(obj1, obj2); // {name: 'zs', age: 18, info: {…}}
obj1.info.sex = "女";
console.log(obj1, obj2); // obj1中的sex改为女

方式二利用JSON的方法

const obj1 = { name: 'zs', age: 18, info: { sex: "男" } }
const obj2 = JSON.parse(JSON.stringify(obj1));
console.log(obj2); // {name: 'zs', age: 18, info: {…}}
obj1.info.sex = "女";
console.log(obj1, obj2); // obj1中的sex改为女

二. 不会销毁的函数执行空间

当函数返回一个复杂数据类型并且函数外部有变量接收这个复杂数据类型时函数执行完毕后函数的执行空间不会销毁

原因函数执行完毕后返回的是一个对象的地址

如果要销毁这个空间只需将接收这个复杂数据类型的变量指向别的位置

function fn() {
    const obj = { name: 'zs', age: 22 }
    return obj;
}
let res = fn();
console.log(res); // {name: 'zs', age: 22}

三. 闭包

闭包函数内的函数
目的在函数外部操作函数里面的私有变量起到保护全局变量的作用

闭包条件

  1. 需要一个不会被销毁的函数执行空间
  2. 需要直接或间接返回一个函数
  3. 内部函数使用外部函数的私有变量

特点

  1. 可以在函数外面访问到函数内部的变量
  2. 延长了变量的生命周期
  3. 内存溢出

浏览器的垃圾回收机制 : 计数 和 标记

当变量进入环境要么计数要么给个标记 如果计数为0 或者标记为离开环境垃圾回收机制进行回收如果无法回收形成内存溢出。

function outer() {
    let a = 100;
    let b = 200;
    function inner() {
        // 3.内部函数使用外部函数的私有变量
        return b;
    }
    // 2.需要直接或间接返回一个函数
    return inner;
}
// 1.需要一个不会被销毁的函数执行空间
// 在outer外面使用了outer里面的变量
const res = outer()();
console.log(res); // 200

闭包案例

// 1. 输出什么
// for (var i = 1; i <= 5; i++) {
//     setTimeout(function () {
//         console.log(i);
//     }, 1000);
// }
for (var i = 1; i <= 5; i++) {
    setTimeout(function () {
        console.log(i);
    }, 0);
}
// 5个6
// 每一次循环的时候都修改的是同一个变量i, 最后循环到了6
// 先执行同步代码同步代码执行完毕之后再执行异步代码

// 2.
// for (let i = 1; i <= 5; i++) {
//     setTimeout(function () {
//         console.log(i);
//     }, 0);
// }
// let 有块级作用域 循环的时候每次循环的i都是不一样的


// 3.
for (var i = 1; i <= 5; i++) {
    function fn(i) {
        window.setTimeout(function () {
            console.log(i);
        }, 0);
    }
    fn(i);
}
// 闭包 内部函数用了外部函数的变量 保存了i这个变量

// 4.
for (var i = 1; i <= 5; i++) {
    // 自执行函数 可以自动执行依次
    ! function (i) {
        window.setTimeout(function () {
            console.log(i);
        }, 0);
    }(i);
}
// 闭包 内部函数用了外部函数的变量把外部函数的变量保存下来

四. 沙箱模式

沙箱模式

  1. 利用闭包
  2. 利用函数内间接返回一个对象
  3. 外部函数返回一个对象对象内书写多个函数
function outer() {
    let a = 100;
    let b = 200;
    // 下面这个对象就是一个沙箱
    const obj = {
        getA() {
            return a;
        },
        getB() {
            return b;
        },
        setA(num) {
            a = num;
        }
    }
    return obj;
}
let res = outer();
// console.log(res); // {getA: ƒ, getB: ƒ, setA: ƒ}
// console.log(res.getA()); // 100
res.setA(500);
console.log(res.getA()); // 500

const res1 = outer()
console.log(res1.getA()); // 100 

五. 沙箱语法糖

沙箱语法糖: 尽可能简化沙箱模式的语法

利用getter 和 setter来进行操作。
操作的时候 对象.设置(获取) 名称

function outer() {
    let a = 100;
    let b = 200;
    const obj = {
        // get关键字  getter获取器用来获取成员a
        get a() {
            return a
        },
        get b() {
            return b
        },
        set a(num) {
            a = num
        }
    }
    return obj;
}
const res = outer();
console.log(res.a); // 100

结束语

希望对您有一点点帮助如有错误欢迎小伙伴指正。
👍点赞您的赞赏是我前进的动力
⭐收藏您的支持我是创作的源泉
✍评论您的建议是我改进的良药
一起加油💪💪💪

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: JavaScriptJava