沐游虞笔记
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • 前端面试题

    • HTML面试题汇总(无答案)
    • HTML面试题汇总
    • CSS 面试题汇总(无答案)
    • CSS 面试题汇总
    • javascript 面试题汇总(无答案)
    • javascript 面试题汇总
    • promise 面试题(无答案)
    • promise 面试题
    • 浏览器面试题汇总(无答案)
    • 浏览器面试题汇总
    • 网络面试题汇总(无答案)
    • 网络面试题汇总
    • 工程化面试题汇总(无答案)
    • 工程化面试题汇总
    • VUE面试题汇总(无答案)
    • VUE面试题汇总
  • 直播课文件

    • 静态页面学习指导
    • 属性的计算过程
    • 层叠继承规则总结
    • BFC
    • JS基础知识回顾
    • DOM 事件的传播机制
    • DOM 事件的注册和移除
    • 阻止事件默认行为
    • 基础领航考试题
    • 基础领航考试题(答案)
    • 2024前端发展
    • JS核心概念学习指导
    • 第三方库与工程化学习指导
    • Vue入门学习指导
    • vue进阶学习指导
    • 前端性能优化
  • 笔面试环节知识讲解

    • 目录
    • 图像处理
    • 图像处理(面试)
    • Webpack构建优化
    • Webpack构建优化(面试)
    • TTS性能优化
    • TTS性能优化(面试)
    • 实时协作
    • 实时协作(面试)
    • 网页复制图片到剪贴板
    • 网页复制图片到剪贴板(面试)
    • vite插件
    • vite插件(面试)
    • 表单数据同步与保持
    • 表单数据同步与保持(面试)
    • 优化虚拟列表
    • 优化虚拟列表(面试)
    • 微前端解决巨石应用
    • 微前端解决巨石应用(面试)
    • DNS解析与优化
    • DNS解析与优化(面试)
    • 前端监控
    • 前端监控(面试)
    • 12.跨标签页通信
    • 12.跨标签页通信(面试)
    • 13.Vite相关优化
    • 13.Vite相关优化(面试)
    • 14.计时器节流问题
    • 14.计时器节流问题(面试)
    • 15.多文件预览支持
    • 15.多文件预览支持(面试)
    • 16.defer优化白屏时间
    • 16.defer优化白屏时间(面试)
  • Vue3整体变化
  • Vue2响应式回顾
  • Vue3响应式变化
  • nextTick实现原理
  • 两道代码题
  • Vue运行机制
  • 渲染器核心功能
  • 事件绑定与更新
  • computed面试题
  • watch面试题
  • 图解双端diff
  • 图解快速dff
  • 最长递增子序列
  • 模板编译器
  • 模板编译提升
  • 组件name作用
  • 路由传参方式
  • 基础篇

    • 序章React介绍
    • JSX基础语法
    • React基本介绍
    • 表单
    • 生命周期
    • 组件与事件绑定
    • 组件状态与数据传递
    • Hooks
    • React--redux介绍
    • React-router介绍
  • 就业篇

    • 属性默认值和类型验证
    • 高阶组件
    • Ref
    • Context
    • Render Props
    • Portals
    • 错误边界
    • 组件渲染性能优化
    • 前端框架的理解
    • Reacti和Vue描述页面的区别
    • 前端框架的分类
    • 虚拟DoM
    • React整体架构
    • React渲染流程
    • Fiber双缓冲
    • MessageChannel
    • Scheduleri调度普通任务
    • Scheduleri调度延时任务
    • 最小堆
    • React中的位运算
    • beginWork工作流程
    • completeWork工作流程
    • 图解diff算法
    • commit工作流程
    • lane模型
    • React中的事件
    • Hooks原理
    • useStateuseReducer.
    • effect相关hook
    • useCallbackuseMemo
    • useRef
    • Update
    • 性能优化策略之eagerState
    • 性能优化策略之bailout
    • bailoutContextAPl
    • 性能优化对日常开发启示
  • 前端监控概述
  • 错误监控
  • 数据上报
  • 页面性能监控
  • 用户行为收集与埋点
  • CSS3手册
  • HTML5手册
  • JavaScript语言提升

    • es补充
    • 事件循环
    • promise基础
    • Promise的链式调用
    • Promise的静态方法
    • async和await
    • Promise相关面试题
  • 网络

    • 客户端与服务器
    • 关于 Apifox 的使用
  • git文档
  • 工程化

    • CommonJS
    • ES module
    • npm文档(包管理)
    • Lass笔记
    • webpack工具
  • canvas详解
  • uinapp笔记
  • 自动化测试
  • oauth2令牌

    • 认识Oauth2
    • 三方应用实现github授权
    • 微信三方应用登录实现
    • 支付宝沙箱支付功能
  • javascript 面试题汇总
  • let、var、const的区别

    • let、var、const的区别
  • 值和引用

    • 值和引用
  • 包装类型

    • 包装类型
  • 数据类型的转换

    • 数据类型的转换
  • 运算符

    • 运算符
  • 原型和原型链

    • 原型和原型链
  • 执行栈和执行上下文

    • 执行栈和执行上下文
  • 作用域和作用域链

    • 作用域和作用域链
  • this指向

    • this指向
  • 垃圾回收与内存泄漏

    • 垃圾回收与内存泄漏
  • 闭包

    • 闭包
  • DOM事件的注册和移除

    • DOM 事件的注册和移除
  • DOM事件的传播机制

    • DOM 事件的传播机制
  • 阻止事件的默认行为

    • 阻止事件默认行为
  • 递归

    • 递归
  • 属性描述符

    • 属性描述符
  • Class和普通构造器的区别

    • class 和构造函数区别
  • 浮点数精度问题

    • 浮点数精度问题
  • 严格模式

    • 严格模式
  • 函数防抖和节流

    • 函数防抖和节流
  • WeakSet和WeakMap

    • WeakSet 和 WeakMap
  • 深浅拷贝

    • 深浅拷贝
      • 经典真题
      • 深拷贝和浅拷贝概念
      • 浅拷贝方法
      • 深拷贝方法
      • 真题解答
  • 函数柯里化

    • 函数柯里化
  • Node的事件循环

    • Node的事件循环
  • eval

    • eval
  • 尺寸和位置

    • 尺寸和位置
  • 更多知识

    • 更多知识
  • JS面试题汇总
  • 深浅拷贝
luzhichang
2023-10-14
目录

深浅拷贝

# 深浅拷贝

# 经典真题

  • 深拷贝和浅拷贝的区别?如何实现

# 深拷贝和浅拷贝概念

首先,我们需要明确深拷贝和浅拷贝的概念。

  • 浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)。浅拷贝只复制指向某个对象的指针(引用地址),而不复制对象本身,新旧对象还是共享同一块内存。

  • 深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。

# 浅拷贝方法

接下来我们来看一下对象有哪些浅拷贝方法。

1. 直接赋值

直接赋值是最常见的一种浅拷贝方式。例如:

var stu = {
    name: 'xiejie',
    age: 18
}
// 直接赋值
var stu2 = stu;
stu2.name = "zhangsan";
console.log(stu); // { name: 'zhangsan', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }

2. Object.assign 方法

我们先来看一下 Object.assign 方法的基本用法。

该方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。

如下:

var stu = {
    name: 'xiejie'
}
var stu2 = Object.assign(stu, { age: 18 }, { gender: 'male' })
console.log(stu2); // { name: 'xiejie', age: 18, gender: 'male' }

在上面的代码中,我们有一个对象 stu,然后使用 Object.assign 方法将后面两个对象的属性值分配到 stu 目标对象上面。

最终得到 { name: 'xiejie', age: 18, gender: 'male' } 这个对象。

通过这个方法,我们就可以实现一个对象的拷贝。例如:

const stu = {
    name: 'xiejie',
    age: 18
}
const stu2 = Object.assign({}, stu)
stu2.name = 'zhangsan';
console.log(stu); // { name: 'xiejie', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }

在上面的代码中,我们使用 Object.assign 方法来对 stu 方法进行拷贝,并且可以看到修改拷贝后对象的值,并没有影响原来的对象,这仿佛实现了一个深拷贝。

然而,Object.assign 方法事实上是一个浅拷贝。

当对象的属性值对应的是一个对象时,该方法拷贝的是对象的属性的引用,而不是对象本身。

例如:

const stu = {
    name: 'xiejie',
    age: 18,
    stuInfo: {
        No: 1,
        score: 100
    }
}
const stu2 = Object.assign({}, stu)
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

3. ES6 扩展运算符

首先我们还是来回顾一下 ES6 扩展运算符的基本用法。

ES6 扩展运算符可以将数组表达式或者 string 在语法层面展开,还可以在构造字面量对象时,将对象表达式按 key-value 的方式展开。

例如:

var arr = [1, 2, 3];
var arr2 = [3, 5, 8, 1, ...arr]; // 展开数组
console.log(arr2); // [3, 5, 8, 1, 1, 2, 3]

var stu = {
    name: 'xiejie',
    age: 18
}
var stu2 = { ...stu, score: 100 }; // 展开对象
console.log(stu2); // { name: 'xiejie', age: 18, score: 100 }

接下来我们来使用扩展运算符来实现对象的拷贝,如下:

const stu = {
    name: 'xiejie',
    age: 18
}
const stu2 = {...stu}
stu2.name = 'zhangsan';
console.log(stu); // { name: 'xiejie', age: 18 }
console.log(stu2); // { name: 'zhangsan', age: 18 }

但是和 Object.assign 方法一样,如果对象中某个属性对应的值为引用类型,那么直接拷贝的是引用地址。如下:

const stu = {
    name: 'xiejie',
    age: 18,
    stuInfo: {
        No: 1,
        score: 100
    }
}
const stu2 = {...stu}
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

4. 数组的 slice 和 concat 方法

在 javascript 中,数组也是一种对象,所以也会涉及到深浅拷贝的问题。

在 Array 中的 slice 和 concat 方法,不修改原数组,只会返回一个浅复制了原数组中的元素的一个新数组。

例如:

// concat 拷贝数组
var arr1 = [1, true, 'Hello'];
var arr2 = arr1.concat();
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 1, true, 'Hello' ]

arr2[0] = 2;
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 2, true, 'Hello' ]
// slice 拷贝数组
var arr1 = [1, true, 'Hello'];
var arr2 = arr1.slice();
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 1, true, 'Hello' ]

arr2[0] = 2;
console.log(arr1); // [ 1, true, 'Hello' ]
console.log(arr2); // [ 2, true, 'Hello' ]

但是,这两个方法仍然是浅拷贝。如果一旦涉及到数组里面的元素是引用类型,那么这两个方法是直接拷贝的引用地址。如下:

// concat 拷贝数组
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = arr1.concat();
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]

arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 19 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]
// concat 拷贝数组
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = arr1.slice();
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]

arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 19 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]

5. jQuery 中的 $.extend

在 jQuery 中,$.extend(deep,target,object1,objectN) 方法可以进行深浅拷贝。各参数说明如下:

  • deep:如过设为 true 为深拷贝,默认是 false 浅拷贝
  • target:要拷贝的目标对象
  • object1:待拷贝到第一个对象的对象
  • objectN:待拷贝到第N个对象的对象

来看一个具体的示例:

<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        const obj = {
            name: 'wade',
            age: 37,
            friend: {
                name: 'james',
                age: 34
            }
        }
        const cloneObj = {};
        // deep 默认为 false 为浅拷贝
        $.extend(cloneObj, obj);
        obj.friend.name = 'rose';
        console.log(obj);
        console.log(cloneObj);
    </script>
</body>

效果:

image-20210831133219541

# 深拷贝方法

说完了浅拷贝,接下来我们来看如何实现深拷贝。

总结一下,大致有如下的方式。

1. JSON.parse(JSON.stringify)

这是一个广为流传的深拷贝方式,用 JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse 方法把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。

示例如下:

const stu = {
    name: 'xiejie',
    age: 18,
    stuInfo: {
        No: 1,
        score: 100
    }
}
const stu2 = JSON.parse(JSON.stringify(stu));
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100 } }
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

这种方式看似能够解决问题,但是这种方法也有一个缺点,那就是不能处理函数。

这是因为 JSON.stringify 方法是将一个 javascript 值(对象或者数组)转换为一个 JSON 字符串,而 JSON 字符串是不能够接受函数的。同样,正则对象也一样,在 JSON.parse 解析时会发生错误。

例如:

const stu = {
    name: 'xiejie',
    age: 18,
    stuInfo: {
        No: 1,
        score: 100,
        saySth: function () {
            console.log('我是一个学生');
        }
    }
}
const stu2 = JSON.parse(JSON.stringify(stu));
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100, saySth: [Function: saySth] }}
console.log(stu2); // { name: 'zhangsan', age: 18, stuInfo: { No: 1, score: 90 } }

可以看到,在原对象中有方法,拷贝之后,新对象中没有方法了。

2. $.extend(deep,target,object1,objectN)

前面在介绍浅拷贝时提到了 jQuery 的这个方法,该方法既能实现浅拷贝,也能实现深拷贝。要实现深拷贝,只需要将第一个参数设置为 true 即可。例如:

<body>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        const obj = {
            name: 'wade',
            age: 37,
            friend: {
                name: 'james',
                age: 34
            }
        }
        const cloneObj = {};
        // deep 设为 true 为深拷贝
        $.extend(true, cloneObj, obj);
        obj.friend.name = 'rose';
        console.log(obj);
        console.log(cloneObj);
    </script>
</body>

效果:

image-20210831134114926

3. 手写递归方法

最终,还是只有靠我们自己手写递归方法来实现深拷贝。

示例如下:

function deepClone(target) {
    var result;
    // 判断是否是对象类型
    if (typeof target === 'object') {
        // 判断是否是数组类型
        if (Array.isArray(target)) {
            result = []; // 如果是数组,创建一个空数组
            // 遍历数组的键
            for (var i in target) {
                // 递归调用
                result.push(deepClone(target[i]))
            }
        } else if (target === null) {
            // 再判断是否是 null
            // 如果是,直接等于 null
            result = null;
        } else if (target.constructor === RegExp) {
            // 判断是否是正则对象
            // 如果是,直接赋值拷贝
            result = target;
        } else if (target.constructor === Date) {
            // 判断是否是日期对象
            // 如果是,直接赋值拷贝
            result = target;
        } else {
            // 则是对象
            // 创建一个空对象
            result = {};
            // 遍历该对象的每一个键
            for (var i in target) {
                // 递归调用
                result[i] = deepClone(target[i]);
            }
        }
    } else {
        // 表示不是对象类型,则是简单数据类型  直接赋值
        result = target;
    }
    // 返回结果
    return result;
}

在上面的代码中,我们封装了一个名为 deepClone 的方法,在该方法中,通过递归调用的形式来深度拷贝一个对象。

下面是 2 段测试代码:

// 测试1
const stu = {
    name: 'xiejie',
    age: 18,
    stuInfo: {
        No: 1,
        score: 100,
        saySth: function () {
            console.log('我是一个学生');
        }
    }
}
const stu2 = deepClone(stu)
stu2.name = 'zhangsan';
stu2.stuInfo.score = 90;
console.log(stu); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 100, saySth: [Function: saySth] }}
console.log(stu2); // { name: 'xiejie', age: 18, stuInfo: { No: 1, score: 90, saySth: [Function: saySth] }}
// 测试2
var arr1 = [1, true, 'Hello', { name: 'xiejie', age: 18 }];
var arr2 = deepClone(arr1)
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]

arr2[0] = 2;
arr2[3].age = 19;
console.log(arr1); // [ 1, true, 'Hello', { name: 'xiejie', age: 18 } ]
console.log(arr2); // [ 2, true, 'Hello', { name: 'xiejie', age: 19 } ]

# 真题解答

  • 深拷贝和浅拷贝的区别?如何实现

参考答案:

  • 浅拷贝:只是拷贝了基本类型的数据,而引用类型数据,复制后也是会发生引用,我们把这种拷贝叫做浅拷贝(浅复制)

    浅拷贝只复制指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存。

  • 深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。

浅拷贝方法

  1. 直接赋值
  2. Object.assign 方法:可以把任意多个的源对象自身的可枚举属性拷贝给目标对象,然后返回目标对象。当拷贝的 object 只有一层的时候,是深拷贝,但是当拷贝的对象属性值又是一个引用时,换句话说有多层时,就是一个浅拷贝。
  3. ES6 扩展运算符,当 object 只有一层的时候,也是深拷贝。有多层时是浅拷贝。
  4. Array.prototype.concat 方法
  5. Array.prototype.slice 方法
  6. jQuery 中的 $.extend:在 jQuery 中,$.extend(deep,target,object1,objectN) 方法可以进行深浅拷贝。deep 如过设为 true 为深拷贝,默认是 false 浅拷贝。

深拷贝方法

  1. $.extend(deep,target,object1,objectN),将 deep 设置为 true
  2. JSON.parse(JSON.stringify):用 JSON.stringify 将对象转成 JSON 字符串,再用 JSON.parse 方法把字符串解析成对象,一去一来,新的对象产生了,而且对象会开辟新的栈,实现深拷贝。这种方法虽然可以实现数组或对象深拷贝,但不能处理函数。
  3. 手写递归

示例代码如下:

function deepCopy(oldObj, newobj) {
    for (var key in oldObj) {
        var item = oldObj[key];
        // 判断是否是对象
        if (item instanceof Object) {
            if (item instanceof Function) {
                newobj[key] = oldObj[key];
            } else {
                newobj[key] = {};  //定义一个空的对象来接收拷贝的内容
                deepCopy(item, newobj[key]); //递归调用
            }

            // 判断是否是数组
        } else if (item instanceof Array) {
            newobj[key] = [];  //定义一个空的数组来接收拷贝的内容
            deepCopy(item, newobj[key]); //递归调用
        } else {
            newobj[key] = oldObj[key];
        }
    }
}

-EOF-

WeakSet 和 WeakMap
函数柯里化

← WeakSet 和 WeakMap 函数柯里化→

Theme by Vdoing | Copyright © 2021-2024 蜀ICP备2024068710号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式