javascript中的深拷贝与浅拷贝

基础概念

在了解深拷贝与浅拷贝的时候需要先了解一些基础知识

核心知识点之 堆与栈

栈(stack)为自动分配的内存空间,它由系统自动释放;

堆(heap)则是动态分配的内存,大小不定也不会自动释放。

基本数据类型存放在栈中,基本数据类型主要是:undefined,boolean,number,string,null。

在 js 中我们对基础数据类型的操作主要是赋值为主

引用类型存放在堆中 引用类型 (object) 其变量实际上

    var a = [1,2,3];
var b = [1,2,3];
console.log(a === b); // false
console.log(a == b); // false

其内存位置不同,尽管内容相同,但本质却不同,可简单的认为是同一户型的两套房子,内部一模一样但并不是同一套房子

传值与传址

基本数据类型的赋值操作,就是只在内存中开辟新的栈内存,将值赋到新的栈中,

而引用类型的赋值是传址 ,即改变指针的指向,故如果两个变量指向同一对象的话,两者间会相互影响

浅拷贝

浅拷贝只复制一层对象的属性,并不包括对象里面的为引用类型的数据。

ES6 当中提供了 Object.assign(target, obj) 方法来进行对拷贝,这一方法进行的是浅拷贝,拷贝的是对象的属性的引用,而不是对象本身,Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它将返回目标对象。

同时 assign() 方法应当注意以下几点

  1. 不会拷贝对象继承的属性、不可枚举的属性、属性的数据属性/访问器属性
  2. 可以拷贝 Symbol 类型
  3. Object.assign()拷贝的是属性值,假如源对象的属性值是一个指向对象的引用,它也只拷贝那个引用值,

来看个例子:

var a = {a : 'old', b : { c : 'old'}}
var b = Object.assign({}, a)
b.a = 'new'
b.b.c = 'new'
console.log(a) // { a: 'old', b: { c: 'new' } }
console.log(b) // { a: 'new', b: { c: 'new' } }

如上面例子,当拷贝的源对象的属性值是一个对象时,拷贝的只是对象的引用值,因此当修改属性值的时候两个对象的属性值都会发生更新

深拷贝

深拷贝是在浅拷贝的基础上,对对象更深的层级进行浅拷贝,也就是递归拷贝的方法

简单的深拷贝

/* ================ 深拷贝 ================ */
function deepClone(initalObj, finalObj) {
var obj = finalObj || {};
for (var i in initalObj) {
var prop = initalObj[i]; // 避免相互引用对象导致死循环,如initalObj.a = initalObj的情况
if(prop === obj) {
continue;
} if (typeof prop === 'object') {
obj[i] = (prop.constructor === Array) ? [] : {};
arguments.callee(prop, obj[i]);
} else {
obj[i] = prop;
}
}
return obj;
}
    // 内部方法:用户合并一个或多个对象到第一个对象
// 参数:
// target 目标对象 对象都合并到target里
// source 合并对象
// deep 是否执行深度合并
function extend(target, source, deep) {
for (key in source)
if (deep && (isPlainObject(source[key]) || isArray(source[key]))) {
//isPlainObject()函数用于判断指定参数是否是一个纯粹的对象
// source[key] 是对象,而 target[key] 不是对象, 则 target[key] = {} 初始化一下,否则递归会出错的
if (isPlainObject(source[key]) && !isPlainObject(target[key]))
target[key] = {} // source[key] 是数组,而 target[key] 不是数组,则 target[key] = [] 初始化一下,否则递归会出错的
if (isArray(source[key]) && !isArray(target[key]))
//isArray() 用于确定传递的值是否是一个 Array。
target[key] = []
// 执行递归
extend(target[key], source[key], deep)
}
// 不满足以上条件,说明 source[key] 是一般的值类型,直接赋值给 target 就是了
else if (source[key] !== undefined) target[key] = source[key]
} // Copy all but undefined properties from one or more
// objects to the `target` object.
$.extend = function(target){
var deep, args = slice.call(arguments, 1);
//slice.call()能将具有length属性的对象转成数组
//第一个参数为boolean值时,表示是否深度合并
if (typeof target == 'boolean') {
deep = target;
//target取第二个参数
target = args.shift()
}
// 遍历后面的参数,都合并到target上
args.forEach(function(arg){ extend(target, arg, deep) })
return target
}

同时在 C++ 当中可以作以类比来提升我们对这一概念的认知

【浅拷贝】只是增加了一个指针,指向已存在对象的内存。

【深拷贝】是增加了一个指针,并新开辟了一块空间,让指针指向这块新开辟的空间。

【浅拷贝】在多个对象指向一块空间的时候,释放一个空间会导致其他对象所使用的空间也被释放了,再次释放便会出现错误

根据以上概念对深浅拷贝作简单的总结

在 javascript 不允许直接访问保存在堆内存中的对象,所以在访问一个对象时,首先得到的是这个对象在堆内存中的地址,然后再按照这个地址去获得这个对象中的值;

深拷贝:将 B 对象拷贝到 A 对象中,包括 B 里面的子对象,

浅拷贝:将 B 对象拷贝到 A 对象中,但不包括 B 里面的子对象

暂时以上

javascript中的深拷贝与浅拷贝的更多相关文章

  1. JavaScript中的深拷贝和浅拷贝!【有错误】还未修改!请逛其他园子!

    JavaScript中的深拷贝和浅拷贝! 浅拷贝 1.浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用.{也就是拷贝的是地址!简而言之就是在新的对象中修改深层次的值也会影响原来的对象!} // 2.深 ...

  2. Javascript中的深拷贝和浅拷贝

    var obj = { a:1, arr: [1,2] }; var obj1 = obj; //浅复制 var obj2 = deepCopy(obj); //深复制 javascript中创建对象 ...

  3. 深入剖析javaScript中的深拷贝和浅拷贝

    如何区分深拷贝与浅拷贝,简单来说,假设B复制了A,当修改A时,看B是否会发生变化,如果B也跟着变了,说明这是浅拷贝,如果B没变,那就是深拷贝:我们先看两个简单的案例: //案例1(深拷贝) var a ...

  4. 理解JavaScript中的深拷贝和浅拷贝

    , num2 = num1;console.log(num1) //1console.log(num2) //1num2 = 2; //修改num2console.log(num1) //1conso ...

  5. 低门槛彻底理解JavaScript中的深拷贝和浅拷贝

    作者 | 吴胜斌 来源 | https://www.simbawu.com/article/search/9 在说深拷贝与浅拷贝前,我们先看两个简单的案例: //案例1var num1 = 1, nu ...

  6. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  7. C语言中的深拷贝和浅拷贝

    //C语言中的深拷贝和浅拷贝 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #inc ...

  8. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

  9. 内功心法 -- Java中的深拷贝和浅拷贝

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...

随机推荐

  1. R语言处理Web数据

    R语言处理Web数据 许多网站提供的数据,以供其用户的消费.例如,世界卫生组织(WHO)提供的CSV,TXT和XML文件的形式的健康和医疗信息报告.基于R程序,我们可以通过编程提取这些网站的具体数据. ...

  2. 【JZOJ3824】【NOIP2014模拟9.9】渴

    SLAF 世界干涸,Zyh认为这个世界的人们离不开水,于是身为神的他要将他掌控的仅仅两个水源地放置在某两个不同的城市.这个世界的城市因为荒芜,他们仅仅保留了必要的道路,也就是说对于任意两个城市有且仅有 ...

  3. Leetcode746.Min Cost Climbing Stairs使用最小花费爬楼梯

    数组的每个索引做为一个阶梯,第 i个阶梯对应着一个非负数的体力花费值 cost[i](索引从0开始). 每当你爬上一个阶梯你都要花费对应的体力花费值,然后你可以选择继续爬一个阶梯或者爬两个阶梯. 您需 ...

  4. 元素的高度(基于vue)

    const viewH =el.target.offsetHeight;//可见高度 const contentH =el.target.scrollHeight;//内容高度 const scrol ...

  5. javaweb学习总结(一) - - JSP取得绝对路径

    在JavaWeb开发中,常使用绝对路径的方式来引入JavaScript和CSS文件,这样可以避免因为目录变动导致引入文件找不到的情况,常用的做法如下: 例如: 1 <!--使用绝对路径的方式引入 ...

  6. hdu1532&&poj1273 最大流

    Dinic算法: 层次图:根据源点到该点的距离建图,这里设相邻的都差1. (下面部分转) 在这幅图中我们首先要增广1->2->4->6,这时可以获得一个容量为2的流,但是如果不建立4 ...

  7. python 不定长参数**kwargs

  8. 伪元素 before 和 after 各种妙用

    大家可能对伪类和伪元素有点迷糊,在介绍具体用法之前,简单介绍下伪类和伪元素.伪类大家听的多了,伪元素可能听到的不是那么频繁,其实 CSS 对这两个是有区分的. 这里整理总结下: 有时你会发现伪类元素使 ...

  9. HDU-6290_奢侈的旅行(Dijstra+堆优化)

    奢侈的旅行 Time Limit: 14000/7000 MS (Java/Others) Memory Limit: 512000/512000 K (Java/Others) Problem De ...

  10. Project Euler Problem 24-Lexicographic permutations

    全排列的生成,c++的next_permutation是O(n)生成全排列的.具体的O(n)生成全排列的算法,在 布鲁迪 的那本组合数学中有讲解(课本之外,我就看过这一本组合数学),冯速老师翻译的,具 ...