Javascript 浅拷贝与深拷贝
在了解JS的浅拷贝与深拷贝之前,我们需要先知道什么是值传递与引用传递。
在JS中,基本类型值的拷贝是按值传递的,而引用类型值的拷贝则是按引用传递的。通过值传递的变量间不会有任何牵连,互相独立;但是引用传递拷贝的变量间则会相互影响,修改其中任何一方所引用的对象的值都会在另一方中体现,之所以会有这样的表现和JS的内存机制有关。
JS的内存也分为堆和栈,但是注意这里的堆栈和数据结构的堆栈是不同的概念。
栈:由系统自动分配,自动回收,效率高,但容量小
堆:由程序员手动分配内存,并且手动销毁(高级语言如JS中有垃圾自动回收机制),效率不如栈,但容量大
JS定义的基本类型值会被存放在栈内存中,JS可以直接访问栈内存,所以访问存放基本类型值的变量可以直接访问到基本类型值。而引用类型因为其大小不固定,系统会为引用类型分配堆内存存放,而只将指向该堆内存空间的指针(引用)存放在栈中,JS不予许直接访问存放引用类型值的堆内存,只能通过访问引用间接的访问引用类型值。这样一来,我们访问引用类型值时,实质上只是在访问它的引用,然后再按照这个引用地址去堆中找到它的实际内容。
因此进行拷贝的时候,对于基本类型值变量,系统会为新变量单独开辟一个新的栈内存空间,并将源变量保存的基本类型值拷贝一份保存到里面。而对于引用类型值,新变量拷贝得到的只是引用对象的引用而已,这么一来,通过两个变量保存的引用访问到的实质就是同一块堆内存,也就是同一个对象。
let person = {
name : "kelly",
love : { sport : "swim", movie : "love story" }
}
let new_person = person
new_person.name = "lin"
console.log( person )
console.log( new_person )
浅拷贝是指在进行对象拷贝的时候,只对对象的第一层键值进行拷贝。
在上面的例子当中,如果不希望修改 new_person 对象的 name 值的时候,源对象的 name 值也跟着一起改变,我们可以尝试对拷贝过程做一些处理,而不再只是简单的直接赋值。
let person = {
name : "kelly",
love : { sport : "swim", movie : "love story" }
}
let new_person = { } function shallowCopy( target, source ){
if( !source || typeof( source ) !== "object" ){
return
}
if( !target || typeof( target ) !== "object" ){
return
}
for( let key in source ){
if( source.hasOwnProperty( key ) ){
target[ key ] = source[ key ]
}
}
} shallowCopy( new_person, person )
new_person.name = "lin"
console.log( new_person )
console.log( person )
这时候我们修改了拷贝对象的 name 值,源对象的 name 值不会再跟着改变了,可是当我们修改属性 sport 的值的时候,源对象的 sport 值却又跟着改变了。
shallowCopy( new_person, person )
new_person.love.sport = "run"
console.log( new_person )
console.log( person )
Object.assign( new_person, person )
new_person.name = "lin"
new_person.love.sport = "run"
console.log( new_person )
console.log( person )
除此之外,Array 的 concat 方法和 slice 方法实现的也是数组对象的浅拷贝。
let arr = [ , [ , , ] ]
let arr_concat = arr.concat( )
let arr_slice = arr.slice( )
arr_concat[ ][ ] = "NO"
console.log( arr ) //[ 1, [ 'NO', 3, 4 ] ]
console.log( arr_concat ) //[ 1, [ 'NO', 3, 4 ] ]
arr_slice[ ][ ] = "NONO!"
console.log( arr ) //[ 1, [ 'NO', 'NONO!', 4 ] ]
console.log( arr_slice ) //[ 1, [ 'NO', 'NONO!', 4 ] ]
数组 arr,arr_concat, arr_slice 的第二个元素引用的都是同一个堆内存对象。
function deepCopy( target, source ){
if( !source || typeof( source ) !== "object" ){
return
}
if( !target || typeof( target ) !== "object" ){
return
}
for( let key in source ){
if( source.hasOwnProperty( key ) ){
if( source[ key ] && typeof( source[ key ] ) === "object" ){
target[ key ] = target.constructor === "Array" ? [ ] : { }
deepCopy( target[ key ], source[ key ] )
} else {
target[ key ] = source[ key ]
}
}
}
} deepCopy( new_person, person )
new_person.name = "lin"
new_person.love.sport = "run"
console.log( new_person )
console.log( person )
var obj = {
a: 1,
b: 2,
c: undefined,
sum: function() { return a + b }
}; var obj2 = JSON.parse( JSON.stringify( obj ) )
console.log( obj2 )
Javascript 浅拷贝与深拷贝的更多相关文章
- JS面试题-<变量和类型>-JavaScript浅拷贝与深拷贝
前言 最开始了解到深浅拷贝是因为准备面试,但那个时候因为在学校做的项目比较少需求也比较简单,所以没有在项目中遇到这类问题,所以对这个问题就属于知道这个知识点,看过相关内容,却没有自己的总结,也没有深入 ...
- 浅谈Javascript 浅拷贝和深拷贝的理解
javascript中存储对象都是存地址的. 浅拷贝:浅拷贝是都指向同一块内存区块,浅拷贝共用同一内存地址,你改值我也变.如果拷贝的对象里面的值是一个对象或者数组,它就是浅拷贝,拷贝的知识引用地址. ...
- javascript浅拷贝和深拷贝
/* 浅拷贝 */ function extend(parent, child) { var i; child = child || {}; for (i in parent) { if (paren ...
- 关于JavaScript的浅拷贝和深拷贝
在 JS 中有一些基本类型像是Number.String.Boolean,而对象就是像这样的东西{ name: 'Larry', skill: 'Node.js' },对象跟基本类型最大的不同就在于他 ...
- Javascript中的浅拷贝和深拷贝
很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现. 在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用 ...
- javascript篇-浅拷贝与深拷贝
理解javascript 的浅拷贝与深拷贝,首先看一下js的数据类型: js有5种基本数据类型:undefined,null,boolean,number,string 还有一种复杂的数据类型(也叫引 ...
- javascript浅拷贝深拷贝理解记录
javascript的深拷贝和浅拷贝问题几乎是面试必问的问题.好记性不如烂笔头,特此来记录一下自己对深拷贝浅拷贝的理解. 顾名思义,拷贝就是copy复制,在js中可以浅而理解为对一个对象或者数组的复制 ...
- javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)
作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝
前言 想写好前端,先练好内功. 栈内存与堆内存 .浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScri ...
随机推荐
- Android screencap截屏指令
查看帮助(注意:有的网友错误使用 screencap -v ,结果差不多,因为系统不能识别-v,就自动打印出帮助信息) # screencap -hscreencap -husage: screenc ...
- json.loads(s) returns error message like this: ValueError: Invalid control character at: line 1 column 33 (char 33)
json.loads(s) returns error message like this: ValueError: Invalid control character at: line 1 colu ...
- python TypeError: unsupported operand type(s) for +: 'int' and 'str' [closed]
TypeError: unsupported operand type(s) for +: 'int' and 'str' [closed] sql="insert into auto_tr ...
- 解决近期linux下yum更新出现HTTP Error 404 NOT FOUND错误的办法
本文转载自:http://tech.lezi.com/archives/47 最近两天使用yum的163源,出现404错误 [root@localhost yum.repos.d]# yum make ...
- A Complete Web Video Solution
A Complete Web Video Solution FLASH . HTML5 . JAVASCRIPT API Support Embed videos from youtube, Vime ...
- 慢日志之二:ERROR 1146 (42S02): Table 'mysql.slow_log' doesn't exist,分析诊断工具之四
去查看最新的slow log,发现没有最新的记录,上去检查slow log是否开启了. MySQL> show variables like '%slow%'; +--------------- ...
- Java-Runoob:Java 异常处理
ylbtech-Java-Runoob:Java 异常处理 1.返回顶部 1. Java 异常处理 异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的. 比如说,你的代码少 ...
- document.getElementById/Name/TagName
document.getElementById 1.getElementById 作用:一般页面里ID是唯一的,用于准备定位一个元素 语法: document.getElementById(id) 参 ...
- 【UVALive】2678 Subsequence(尺取法)
题目 传送门:QWQ 分析 一开始没看到都是正整数根本不会做...... 看到了就是水题了.(但还是sb WA了一发) 尺取法搞一搞 代码 #include <bits/stdc++.h> ...
- 【BZOJ】1913: [Apio2010]signaling 信号覆盖(计算几何+计数)
题目 传送门:QWQ 分析 人类智慧题,不会做...... 详细题解1 详细题解2 总体思路是考虑四边形 讨论凹四边形凸四边形,最后加一个单调性优化省掉个$ O(n) $ 代码 代码感觉好短 ...