
JavaScript的浅拷贝和深拷贝
值比较:基本数据类型的比较是按值进行的。 引用地址比较:引用类型的比较是按引用地址进行的。
发布日期:2021-05-04 17:17:13
浏览次数:35
分类:精选文章
本文共 5019 字,大约阅读时间需要 16 分钟。
JavaScript中的浅拷贝与深拷贝
前言
在学习JavaScript时,理解数据类型的基础知识是必不可少的。JavaScript中的数据类型分为基本数据类型和引用类型。基本数据类型如number
、string
、boolean
等是按值访问的,且值是不可变的;而引用类型如object
、array
等是按引用访问的,且值是动态可变的。
数据类型的比较特点
基于以上特点,我们可以初步想到,所谓的浅拷贝和深拷贝可能分别对应于值的拷贝和引用的拷贝。基本数据类型的拷贝不需要区分,因为它们都是按值拷贝的。对于引用类型的拷贝,我们需要明确其是浅拷贝还是深拷贝。
浅拷贝
浅拷贝是指只复制对象的一层属性,而不深入处理其内部的引用类型。浅拷贝的过程中,对象的引用会被拷贝,但其内部的对象、数组等引用类型仍然指向原对象的内存地址。
数组的浅拷贝
要实现数组的浅拷贝,有多种方法可以选择:
slice
方法:var zxxArr = ["One", "Two", "Three"];var zxxArrs = zxxArr.slice(0);zxxArrs[1] = "love";console.log(zxxArr); // ["One", "Two", "Three"]console.log(zxxArrs); // ["One", "love", "Three"]
concat
方法:- 扩散运算符(ES6):
- 手动循环拷贝:
Object.assign
方法:- ES6对象扩展语法:
JSON.stringify
与JSON.parse
:- 循环递归拷贝:
- jQuery或Zepto的
.extend
方法: - 性能问题:对于大型复杂对象,使用
JSON.stringify
可能会导致性能问题。 - 循环引用:如果对象中存在循环引用,如
const a = {val: 2}; a.target = a;
,深拷贝会导致系统栈溢出。 - 函数和原型成员:深拷贝过程中,对象的函数和原型成员会被丢失。
var zxxArr = ["One", "Two", "Three"];var zxxArrs = zxxArr.concat();zxxArrs[1] = "love";console.log(zxxArr); // ["One", "Two", "Three"]console.log(zxxArrs); // ["One", "love", "Three"]
var zxxArr = ["One", "Two", "Three"];var zxxArrs = [...zxxArr];zxxArrs[1] = "love";console.log(zxxArr); // ["One", "Two", "Three"]console.log(zxxArrs); // ["One", "love", "Three"]
对象的浅拷贝
对象的浅拷贝同样可以通过多种方法实现:
function simpleCopy(obj1) { var obj2 = Array.isArray(obj1) ? [] : {}; for (let i in obj1) { if (obj1.hasOwnProperty(i)) { obj2[i] = obj1[i]; } } return obj2;}var zxxObj = { age: 18, nature: ['smart', 'good'], names: { name1: 'zxx', name2: 'xka' }, love: function () { console.log('zxx is a great girl'); }};var newZxxObj = simpleCopy(zxxObj);newZxxObj.age = 8;newZxxObj.nature.push('why');newZxxObj.names.name1 = 'why zxx';newZxxObj.love = function () { console.log('zxx is 18 years old');};console.log(zxxObj.age); // 18console.log(zxxObj.nature); // ["smart", "good", "why"]console.log(zxxObj.names); // {name1: "why zxx", name2: "xka"}console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}
var zxxObj = { age: 18, nature: ['smart', 'good'], names: { name1: 'zxx', name2: 'xka' }, love: function () { console.log('zxx is a great girl'); }};var newZxxObj = Object.assign({}, zxxObj);newZxxObj.age = 8;newZxxObj.nature.push('why');newZxxObj.names.name1 = 'why zxx';newZxxObj.love = function () { console.log('zxx is 18 years old');};console.log(zxxObj.age); // 18console.log(zxxObj.nature); // ["smart", "good", "why"]console.log(zxxObj.names); // {name1: "why zxx", name2: "xka"}console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}
var zxxObj = { age: 18, nature: ['smart', 'good'], names: { name1: 'zxx', name2: 'xka' }, love: function () { console.log('zxx is a great girl'); }};var newZxxObj = {...zxxObj};newZxxObj.age = 8;newZxxObj.nature.push('why');newZxxObj.names.name1 = 'why zxx';newZxxObj.love = function () { console.log('zxx is 18 years old');};console.log(zxxObj.age); // 18console.log(zxxObj.nature); // ["smart", "good", "why"]console.log(zxxObj.names); // {name1: "why zxx", name2: "xka"}console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}
深拷贝
深拷贝是对对象及其所有子对象进行逐层拷贝,确保新对象与原对象完全独立,不互相影响。
深拷贝的实现方法
var zxxObj = { age: 18, nature: ['smart', 'good'], names: { name1: 'zxx', name2: 'xka' }, love: function () { console.log('zxx is a great girl'); }};var newZxxObj = JSON.parse(JSON.stringify(zxxObj));newZxxObj.age = 8;newZxxObj.nature.push('why');newZxxObj.names.name1 = 'why zxx';newZxxObj.love = function () { console.log('zxx is 18 years old');};console.log(zxxObj.age); // 18console.log(zxxObj.nature); // ["smart", "good"]console.log(zxxObj.names); // {name1: "zxx", name2: "xka"}console.log(zxxObj.love); // ƒ () {console.log('zxx is a great girl')}console.log(newZxxObj); // {age: 8, nature: Array(2), names: Object, love: Function}
function deepClone(initalObj, finalObj) { var obj = finalObj || {}; for (var i in initalObj) { var prop = initalObj[i]; if (prop === obj) { continue; } if (typeof prop === 'object') { obj[i] = (prop.constructor === Array) ? [] : {}; arguments.callee(prop, obj[i]); } else { obj[i] = prop; } } return obj;}var zxxObj = { age: 18, nature: ['smart', 'good'], names: { name1: 'zxx', name2: 'xka' }, love: function () { console.log('zxx is a great girl'); }};var newZxxObj = deepClone(zxxObj);newZxxObj.age = 8;newZxxObj.names.name1 = 'newzxx';console.log(zxxObj);console.log(newZxxObj);
var $ = require('jquery');var newObj = $.extend(true, {}, obj);
深拷贝的注意事项
总结
在实际应用中,根据需求选择合适的拷贝方法非常重要。浅拷贝适用于不需要深入拷贝子对象的场景,而深拷贝则适用于需要确保对象独立性的情况。无论是哪种拷贝方式,都需仔细分析对象的结构,确保拷贝过程中的准确性和完整性。
发表评论
最新留言
不错!
[***.144.177.141]2025年05月08日 22时51分23秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
PHP系列:PHP 基础编程 2(时间函数、数组---实现登录&注册&修改)
2025-03-28
PHP系列:使用PHP实现登录注册功能的完整指南
2025-03-28
Python&aconda系列:(W&L)Conda使用faiss-gpu报错及解决办法、安装numpy的坑、cmd执行Python脚本找不到第三方库、安装tensorflow-gpu时遇到的from
2025-03-28
"WARNING: Increasing RAM size to 1GB" and "Cannot set up guest memory 'xxx.ram': Invalid argument".
2025-03-28
#if 0 #elif 1 #else #endif 用法
2025-03-28
(反射+内省机制的运用)简单模拟spring IoC容器的操作
2025-03-28
(转)tomcat7.0 manager app和host manager web管理
2025-03-28
.Net(C#)实现异步编程
2025-03-28
.Net中webBrowser控件JS交互
2025-03-28
.Net中webBrowser控件指定IE版本
2025-03-28
02-Docker镜像分类及操作秘籍,轻松掌握导出、导入、删除
2025-03-28
04-docker-commit构建自定义镜像
2025-03-28
04-docker系列-commit构建自定义镜像
2025-03-28
05-docker系列-使用dockerfile构建镜像
2025-03-28
05-如何通过Dockerfile实现高效的应用容器化?
2025-03-28