要用递归实现深拷贝,首先说说什么是深拷贝和浅拷贝

浅拷贝:一个值赋给另一个值,当原先的值不改变地址的情况下改变数据,另一个值跟着变
深拷贝:一个值赋给另一个值,当原先的值不改变地址的情况下改变数据,另一个值不变
 
注意 : 强调一点,原先的值不改变地址的情况下改变数据,如果是改了地址的改变,那将用另一个值的改变与否判断深拷贝浅拷贝毫无意义
 
// 举一个简单的例子---以下的obj,obj2可以看做是这里的obj,obj2

var obj = {
name : 'zs',
age : 18
}
// 浅拷贝
var obj2 = obj;
obj.name = 'ls';
console.log(obj2) // { name : 'ls' , age : 18 }

这是浅拷贝,单单就是把obj的地址给了obj2,obj改了,obj2也要改。再来说说这obj改了,这里面有点不同。要么 obj改了属性(数组就是改了元素),要么干脆obj指向另一个地址,例如:obj = 1;针对第一种就是深浅拷贝可以作为判断依据的,根据改了之后obj2改不改就可以看出深拷贝(不改)还是浅拷贝(改了)。第二种不管深浅拷贝的因为obj的地址变了,obj再怎么改都不会影响obj2,因此obj2肯定不会变,深浅拷贝看不出来的

var obj = {
name : 'zs',
age : 18
}
var obj2 = obj;
// obj 自己地址都变了,再怎么折腾影响不了obj2了
obj = 1;
console.log(obj2) // { name : 'zs' , age : 18 }

//  以上 obj可以看做第一个对象(数组) ,obj2 可以看做第二个对象(数组) ,为什么不说函数呢? 因为函数本身办法改内容,声明的时候已经确定好函数体了,你还能有神通在不改变声明函数的函数体前提下,后续添加函数体语句?如果可以,请教教我,说真的!

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

以下重点说说深拷贝 : 说白了深拷贝的目的就是不想让obj来影响obj2,有点过河拆桥的意思,把好处或爱情给了另一个人,另一个人却不想让你打扰她(说多了是泪)

针对以下三种常见情况提供三种方式进行深拷贝 : 

很纯的对象 : 属性值没有数组、对象的   var obj2 = Object.assgin({ }, obj)

没有方法的对象 (没有方法在内,可以有数组和对象充当属性值) : var obj2 = JSON.parse(JSON.stringify(obj))

        var u = {
o : {'name' : 'zs'},
i : 5
}
var v = JSON.parse(JSON.stringify(u))
u.o.name = 'ls';
console.log(u,v); // v的o属性中的name还是'zs'

③ 递归( 通用,从底层的角度 ) 基本思想 : 判断obj 是基本类型就简单赋值,对象(数组)的话 ,创建一个空[ ](obj是对象)或空{ }(obj是对象),再判断obj的属性有没有对象(数组),有递归调用,没有简单赋值,直到全部赋值完毕,返回赋值后的new_obj , 看不懂没关系下面代码有注释,绝对可以看懂

var obj = {
arr1 : [1,2,3],
fn: function(){
console.log('我是一个方法')
},
a : '我是普通属性'
} // 现在我要把obj字面量创建里的属性深拷贝( 属性值是引用类型也要深拷贝 )
function deepClone(obj){
// 根据类型制造一个新的数组或对象 => 指向一个新的空间
// 由于数组的typeof也是'object',所以用Array.isArray(obj)
var new_obj = Array.isArray(obj) ? [] : {};
// 首先判断obj的类型
// 普通类型
if( typeof obj != 'object' ){
// 这里不能直接返回obj,不然就是浅拷贝的性质
return new_obj = obj
}
//引用类型
//数组
if(obj instanceof Array ){
for(i = 0; i < obj.length; i++ ){
new_obj[i] = obj[i];
if(typeof new_obj[i] == 'object'){
deepClone(new_obj[i])
}
}
}else{ //对象
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
// 对象中的数组和对象
if (typeof obj[key] == 'object') {
new_obj[key] = deepClone(obj[key]);
}else{//对象中没有引用类型
new_obj[key] = obj[key]
}
}
}
}
return new_obj;
}
var deepClone = deepClone(obj);
console.log(deepClone);
// 测试是不是深拷贝
obj.fn = '我改变了方法属性';
console.log(obj); //{arr1: Array(3), fn: ƒ, a: "我是普通属性", c: "我新增了一个属性"}
console.log(deepClone); // 还是 {arr1: Array(3), fn: ƒ, a: "我是普通属性"}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

本文原创,仅供学习使用

递归实现深拷贝( 只要学过js递归,看不懂找我包会 )的更多相关文章

  1. js递归遍历多维数组并在修改数组的key后返回新的多维数组

    我司最近正在用VUE做一个基于用户权限显示不同左侧菜单的后台管理系统,接口会根据用户的权限不同返回不同的菜单名称.URL等,前端要将这些菜单名称及URL动态添加到系统的左侧,这里就用到了vue-rou ...

  2. 【Vue.js实战案例】- Vue.js递归组件实现组织架构树和选人功能

    大家好!先上图看看本次案例的整体效果. 浪奔,浪流,万里涛涛江水永不休.如果在jq时代来实这个功能简直有些噩梦了,但是自从前端思想发展到现在的以MVVM为主流的大背景下,来实现一个这样繁杂的功能简直不 ...

  3. js 递归调用

    js递归调用 function fact(num) { ) { ; } else { ); } } 以下代码可导致出错: var anotherFact = fact; fact = null; al ...

  4. 关于js回调方法 js递归时使用方法

    js中递归调用本身可以这样: function a1(n){ a1(n)}但是如果需要在参数n进行自增的情况下判断会出错: function a1(n){ if(n>10) return 'aa ...

  5. javascript之闭包,递归,深拷贝

    闭包 理解:a函数执行后return出b函数且b函数可以访问a函数的数据 好处:子函数存储在复函数内部,子函数执行完不会被自动销毁 坏处:占用内存比较大 ex: function bibao(){ v ...

  6. JS递归及二叉搜索树的移除节点

    1递归含义:在某时某刻某个条件下调用包含自己的函数 2:注意点:⑴递归过程中一定要加限制条件,要不然会陷入死循环: 死循环eg: function f(someP){ f(somP); } f(4); ...

  7. SQL Server中公用表表达式 CTE 递归的生成帮助数据,以及递归的典型应用

    本文出处:http://www.cnblogs.com/wy123/p/5960825.html 我们在做开发的时候,有时候会需要一些帮助数据,必须需要连续的数字,连续间隔的时间点,连续的季度日期等等 ...

  8. 【高德地图API】从零开始学高德JS API(七)——定位方式大揭秘

    原文:[高德地图API]从零开始学高德JS API(七)——定位方式大揭秘 摘要:关于定位,分为GPS定位和网络定位2种.GPS定位,精度较高,可达到10米,但室内不可用,且超级费电.网络定位,分为w ...

  9. 【高德地图API】从零开始学高德JS API(八)——地址解析与逆地址解析

    原文:[高德地图API]从零开始学高德JS API(八)——地址解析与逆地址解析 摘要:无论是百度LBS开放平台,还是高德LBS开放平台,其调用量最高的接口,必然是定位,其次就是地址解析了,又称为地理 ...

随机推荐

  1. vue-cnodejs

    感谢那些无私开源的程序员,你们是最可爱的人儿~~~~ //根app app.js <template> <div id="app"> <v-heade ...

  2. CDH5.13.1安装

    文件下载 Cloudera Manager 地址:http://archive.cloudera.com/cm5/cm/5/ 这里下载的是5.13.1的版本,https://archive.cloud ...

  3. Docker镜像部分详解

    拉取镜像: docker pull [选项] [Docker Registry 地址[:端口号]/]仓库名[:标签] Docker 镜像仓库地址:地址的格式一般是 [:端口号].默认地址是 Docke ...

  4. 2017 ACM-ICPC 亚洲区(西安赛区)网络赛C. Sum【脑洞题】

    限制:1000ms 32768K Define the function S(x) for xx is a positive integer. S(x) equals to the sum of al ...

  5. AtCoder Grand Contest 019 B - Reverse and Compare【思维】

    AtCoder Grand Contest 019 B - Reverse and Compare 题意:给定字符串,可以选定任意i.j且i<=j(当然i==j时没啥卵用),然后翻转i到j的字符 ...

  6. 【批量添加】-SqlBulkCopy语句 标签: sql批量添加 2015-12-20 14:39 1367人阅读 评论(33)

    上篇博客我们介绍了通过拼接sql字符串的方法来对sql数据库进行批量添加,但是通过语句拼接insert语句有个缺点,就是每次最多只能添加1000条.当时我们另外一个界面也用到了批量添加,但是这个界面轻 ...

  7. 【牛腩视频】之SQL触发器 标签: 数据库 2015-05-23 09:44 1339人阅读 评论(40) 收藏

    之前在学习机房管理系统.net版的时候,已经写过了关于数据库的操作,但是现在开始学习牛腩,才发现之前自己理解的太浅显,很多东西看似好像会了,不去实际操作一下,不把代码从头到尾敲出来,到头来还是不会,所 ...

  8. Redis源码解析:10scan类命令的实现

    像keys或者smembers命令,需要遍历数据集合中的所有元素.在一个大的数据库中使用,可能会阻塞服务器较长的一段时间,造成性能问题,因此不适用与生产环境. 在Redis2.8.0中引入了scan类 ...

  9. Redis 5.0新功能介绍

    Redis 5.0 Redis5.0版是Redis产品的重大版本发布,我们先看一下它的最新特点: 新的流数据类型(Stream data type) https://redis.io/topics/s ...

  10. 11-2 css盒模型和浮动以及矢量图用法

    一 盒模型 1属性 width:内容的宽度 height: 内容的高度 padding:内边距,边框到内容的距离 border: 边框,就是指的盒子的宽度 margin:外边距,盒子边框到附近最近盒子 ...