Javascript中的浅拷贝和深拷贝
很多开发语言中都有浅拷贝和深拷贝的说法,这里简单区分一下它们在Javascript中的区别,以及jQuery中深拷贝的实现。
在谈浅拷贝和深拷贝之前,先要屡清楚Javascript中的按值访问和按引用访问这两个概念。
按值访问是针对基本类型(string、number、boolean、null、undefined)。基本类型以值的形式被存放在栈内存中,我们通过变量操作的是栈内存中实际的值。
按引用访问时针对引用类型(Object、Array、Date、RegExp、Function)。引用类型以对象的形式被存放在堆内存中,我们通过变量操作的堆内存中对象的引用,也就是说,变量中保存的是一个指针,指向内存中的某个位置。
--------------------------分割线--------------------------
浅拷贝与深拷贝的区别是针对引用类型而言的,浅拷贝只是拷贝了对象表面上的一层,而深拷贝是拷贝了对象的所有层级。
那这两种方式,区别在哪里呢?
举个例子:
var arr = ['a', 'b']; var newArr = arr; // newArr拷贝了arr console.log(newArr); // ['a', 'b'] arr.push('c'); console.log(newArr); //['a', 'b', 'c']
以上代码是一个简单的浅拷贝。
由于arr是一个数组,数组内部保存了两个string类型的值。newArr通过直接赋值得到该数组的引用,此时newArr和arr所指向的是内存中的同一个位置,所以arr的操作反应到内存中数组的改变,也就导致了newArr的改变。
下面来看看深拷贝:
var arr = ['a', 'b']; var newArr = []; newArr[0] = arr[0]; newArr[1] = arr[1]; console.log(newArr); // ['a', 'b'] arr.push('c'); console.log(newArr); //['a', 'b']
以上代码是一个简单的深拷贝。
我们发现此时,arr的改变并没有影响到newArr,原因就在于,这次我们是先定义了一个空数组newArr(在内存中开辟了新的位置),此时newArr与arr所指向的是内存中不同的位置,然后我们对数组中的string类型的值进行赋值操作,得到了最后的newArr。
那么,我们现实中遇到的拷贝问题不会是这简单的数组,可能会像这样:
var person1 = { name: 'Mike', age: 5, friends: [ 'Jack', 'Candy' ] };
对于这个例子,如果我们想实现深拷贝,就需要遍历person1的所有属性。由于name、age是基本类型,所以直接赋值没有问题,但是friends是数组,也就是引用类型,那么我们也需要遍历friends,万一friends数组的某个元素是引用类型,那么继续,以此类推......
所以,实现深拷贝并不是那么容易的,下面我们来看看jQuery中是如何处理的。
// 这是一个用来扩展jQuery的方法,jQuery.extend([boolean], arg1, arg2, ...) // 第一个参数可选,表示进行浅拷贝或深拷贝,默认false // 第二个参数是拷贝后的存放目标(后面简称拷贝目标) // 第三个及以后的参数都是拷贝对象(后面简称拷贝对象) jQuery.extend = jQuery.fn.extend = function () { var options, name, src, copy, copyIsArray, clone, target = arguments[0] || {}, i = 1, length = arguments.length, deep = false; if (typeof target === "boolean") { deep = target; target = arguments[i] || {}; i++; } if (typeof target !== "object" && !jQuery.isFunction(target)) { target = {}; } if (i === length) { target = this; i--; } // 以下开始重点 // 遍历arg2, arg3, ... for (; i < length; i++) { // 如果拷贝对象不是null,并存放到变量options中 if ((options = arguments[i]) != null) { // 遍历拷贝对象的属性 for (name in options) { src = target[name]; // 拷贝目标中的相应属性值 copy = options[name]; // 拷贝对象中的相应属性值 // 防止循环引用 if (target === copy) { continue; } // 如果deep(布尔参数)为true,也就是要进行深拷贝,并且拷贝对象中该属性值是数组或者对象 if (deep && copy && (jQuery.isPlainObject(copy) || (copyIsArray = Array.isArray(copy)))) { if (copyIsArray) { // 如果该属性值是数组 copyIsArray = false; clone = src && Array.isArray(src) ? src : []; // 拷贝目标中该属性值 } else { // 如果该属性值是对象 clone = src && jQuery.isPlainObject(src) ? src : {}; } // 以该属性值作为拷贝对象,递归调用jQuery.extend() target[name] = jQuery.extend(deep, clone, copy); // 否则浅拷贝 } else if (copy !== undefined) { target[name] = copy; // 直接赋值 } } } } // 返回最终的拷贝目标 return target; };
欢迎补充和指正
Javascript中的浅拷贝和深拷贝的更多相关文章
- javascript中的浅拷贝和深拷贝(拷贝引用和拷贝实例)
作者:千锋教育链接:https://www.zhihu.com/question/23031215/answer/326129003来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请 ...
- javascript中的浅拷贝和深拷贝 分类: JavaScript 2015-05-07 15:29 831人阅读 评论(1) 收藏
1.js对象浅拷贝 简单的赋值就是浅拷贝.因为对象和数组在赋值的时候都是引用传递.赋值的时候只是传递一个指针. 看下面的实例代码: var a = [1,2,3]; var b =a ; var te ...
- 【转】JAVA中的浅拷贝和深拷贝
原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...
- javascript中的堆栈、深拷贝和浅拷贝、闭包
堆栈 在javascript中,堆内存是用来存放引用类型的空间环境 而栈内存,是存储基本类型和指定代码的环境 在对象中的属性名具有唯一性,数字属性名=字符串属性名,但是在测试的时候你会发现,好像所有属 ...
- javascript中的浅拷贝ShallowCopy与深拷贝DeepCopy
拷贝,在js中,分为浅拷贝和深拷贝.这两者是如何区分的呢?又是如何实现的呢? 深浅拷贝的区分 首先说下,在js中,分为基础数据类型和复杂数据类型, 基础数据类型:Undefined.Null.Bool ...
- js中的浅拷贝和深拷贝
说说最近所学:浅拷贝和深拷贝也叫做浅克隆和深克隆,深浅主要针对的是对象的"深度",常见的对象都是"浅"的,也就是对象里的属性就是单个的属性,而"深&q ...
- 浅谈JS中的浅拷贝与深拷贝
前端工程师应该都比较熟悉浅拷贝和深拷贝的概念,在日常业务代码的过程中,特别是做数据处理的时候,经常行的会遇到,比如如何在不修改原对象的基础上,重新生成一个一模一样的对象,加以利用,又或是,如何巧妙地运 ...
- C# 中的浅拷贝与深拷贝
Ø 简介 在 C# 中分为两种数据类型,值类型和引用类型.我们知道,值类型之间赋值是直接将值赋值给另一个变量,两个变量值的改变都互不影响:而引用类型赋值则是将引用赋值给另一个变量,其中一个变量中的成 ...
- Javascript/js 的浅拷贝与深拷贝(复制)学习随笔
js变量的数据类型值分基本类型值和引用类型值. 在ES6(ECMAScript6)以前,基本数据类型包括String.Number.Boolean.Undefined.Null. 基本类型值的复制(拷 ...
随机推荐
- RxSwift 系列(五) -- Filtering and Conditional Operators
前言 本篇文章将要学习RxSwift中过滤和条件操作符,在RxSwift中包括了: filter distinctUntilChanged elementAt single take takeLast ...
- [C++ Calculator 项目] 基础运算实现
Calculator V1.1 注:这是C++计算器项目第二部分-运算 [基于初始部分增改而得] 源文件已上传至github 主要问题: Ⅰ.运算实现的问题在于( ) + - * /的优先级的处理,以 ...
- 【HTML】模板
<!DOCTYPE html> <head> <base href="http://www.w3school.com.cn/i/" target=&q ...
- ML(1)--概念理解
机器是如何模拟人来学习的? 人: observations===>learning===>skill 人从出生开始经过大量的观察(也可能经过身边的的指导)进行学习然后得到相应的技能(比如 ...
- C#的基础数据类型
一.概述 C# 的类型系统是统一的,因此任何类型的值都可以按对象处理.C# 中的每个类型直接或间接地从 object 类类型派生,而 object 是所有类型的最终基类.C#的数据类型主要分为三类:值 ...
- Asp.net MVC Razor常见问题及解决方法
没有经验的童鞋就是这样磕磕碰碰出来的经验. 1,Datatype的错误提示消息无法自定义 这也许是Asp.net MVC的一个Bug.ViewModel中定义了DataType为Date字段: [Re ...
- ES6数组扩展
前面的话 数组是一种基础的JS对象,随着时间推进,JS中的其他部分一直在演进,而直到ES5标准才为数组对象引入一些新方法来简化使用.ES6标准继续改进数组,添加了很多新功能.本文将详细介绍ES6数组扩 ...
- Mysql的JDBC
Java程序可以通过JDBC链接数据库,通过JDBC可以方便的访问数据库,不必为特定的数据库编写专门的程序. 需要先配置mysql-connector-java-5.0.8-bin.jar 使用JDB ...
- reversing.kr easy crack 之write up
之前学逆向感觉学得一踏糊涂,这阶段好多师傅带我,一定要好好学,重新开始,认真学习. 来看打开可执行文件: 用ollydbg载入,单步执行后停到了入口点: 分析入口点,并没有加壳,于是F9执行程序,跳出 ...
- Spring+SpringMVC+MyBatis+easyUI整合基础篇(四)代码简化
点这里看实际效果! 账密:admin 123456 敲了一天的代码,有些烦,感觉前一篇文章写的太笼统了,哈哈哈. 本来呢,也就是刚开始写,所以很多细节都想不到,源码也放上来了,自己动动手应该也 ...