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. JavaScript--微博发布效果

    效果图: 实现思路:  当发布按钮被点击时,又会分为三种情况 1.如果输入的内容为空,弹出提示:不能发布空微博 2.如果输入的文字超过120,弹出提示,微博内容不能超过120 3.正常发布微博到列表里 ...

  2. Word画线条5大技巧,简单实用!

    [Word画线条5大技巧,简单实用!]1.输入三个“=”,回车,就是一条双直线:2.输入三个“~”,回车,就是一条波浪线:3.输入三个“”回车,就是一条虚线:4.输入三个“-”,回车,就是一条直线:5 ...

  3. Path Sum 深度搜索

    Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all ...

  4. LRM-00109: could not open parameter file '/u01/app/oracle/product/12.1.0/db_1/dbs/initepps.ora'

    安装好oracle后,起动时报如下错误: [oracle@Oracle-A ~]$ export ORACLE_SID=ORCL [oracle@Oracle-A ~]$ sqlplus / as s ...

  5. LeetCode107 Binary Tree Level Order Traversal II

    Given a binary tree, return the bottom-up level order traversal of its nodes' values. (ie, from left ...

  6. Calendar类实现当前日期的日历

    package com.sxt.home1; import java.text.DateFormat; import java.text.ParseException; import java.tex ...

  7. struts.xml中的结果类型与视图

    实际上在Struts2框架中,一个完整的结果视图配置文件应该是: ? 1 2 3 4 5 <action name="Action名称" class="Action ...

  8. 唯一索引与非唯一索引区别(UNIQUE INDEX, NON-UNIQUE INDEX)

    索引是我们经常使用的一种数据库搜索优化手段.适当的业务操作场景使用适当的索引方案可以显著的提升系统整体性能和用户体验.在Oracle中,索引有包括很多类型.不同类型的索引适应不同的系统环境和访问场景. ...

  9. SQL server无法绑定由多个部分绑定的标示符

    原因https://blog.csdn.net/wolfalcon/article/details/54578215给了我启发,原来有犯错在insert和update的使用上了对于已存在的表(表中有字 ...

  10. Fragment学习(一) :生命周期

    一. 何为Fragment Fragment是activity的界面中的一部分或一种行为.你可以把多个Fragment们组合到一个Activity中来创建一个多面界面,并且你可以在多个Activity ...