深浅拷贝知识在我们的日常开发中还算是用的比较多,但是之前的状态一直都是只曾听闻,未曾使用(其实用了只是自己没有意识到),所以今天来跟大家聊一聊js的深浅拷贝;

  首先我们来了解一下javascript的数据类型,在ES5版本的js中我们的javascript一共有6种数据类型,分别是:

  Number(数值型)、String(字符串)、Boolean(布尔型)、Object(对象,object和array都属于Object类型)、null、undefined

  我们日常使用的javascript深浅拷贝主要是面向Object引用类型进行拷贝;

  

  我们知道了js的深浅拷贝面对的执行操作对象,然后我们再来看一下深浅拷贝的概念:

     拷贝顾名思义就是复制,内存中一共分为栈内存和堆内存两大区域,所谓深浅拷贝主要是对javascript引用类型数据进行拷贝一份,浅拷贝就是引用类型数据相互赋值之后,例obj1=obj2;如果后面的操作中修改obj1或者obj2,这个时候数据是会进行相应的变化的,因为在内存中引用类型数据是存储在堆内存中,堆内存中存放的是引用类型的值,同时会有一个指针地址指向栈内存,两个引用类型数据地址一样,如果其中一个发生变化另外一个都会有影响;而深拷贝则不会,深拷贝是会在堆内存中重新开辟一块空间进行存放;

    基本类型复制:

var a = 1;
var b = a;//复制
console.log(b)//
a = 2;//改变a的值
console.log(b)//
console.log(a) //

  因为a,b都是属于基本类型,基本类型的复制是不会影响对方的,因为基本类型是每一次创建变量都会在栈内存中开辟一块内存,用来存放值,所以基本类型进行复制是不会对另外一个变量有影响的;

    引用类型复制:

      引用类型的复制我们分为数组的复制和对象的复制两个方面来进行讲解:

      js的浅拷贝:

var arr1 = ['red','green'];
var arr2 = arr1;//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//['red','green','black']
console.log(arr1) //["red", "green", "black"]

    上面的案例是javascript数组的浅拷贝,通过上面的知识我们可以看知道数组是引用类型数据,引用类型数据复制是会进行相互影响的,我们看到arr1.push('black')添加了一个新的子项,因为上面var arr2=arr1这行代码是将两个引用类型数据的地址指针指向了同一块堆内存区域,所以不管是arr1还是arr2修改,任何一个一个改动两个数组都是会互相产生影响的;上面的那种直接赋值方式的复制就是我们常说的引用类型的浅拷贝;

     关于深拷贝很多同学都误以为js的原生方法concat、slice是属于深拷贝,其实不是的;js的原生方法concat、slice都是仅适用于一维数组,一旦到了二维数组或者多维数组中就会出现问题,就出现拷贝的不够彻底导致还是会发生数据的相互牵引问题;

        slice:

var arr1 = ['red','green'];
var arr2 = arr1.slice(0);//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//["red", "green"]
console.log(arr1)//["red", "green", "black"]

      js原生的方法slice会返回一个新的数组,上述代码乍一看会以为是深拷贝,因为arr2和arr1相互复制和牵引,而当arr1调用了push方法添加了新数组子项的时候,arr2没有发生变化;是的,这是符合深拷贝的特性,但是拷贝的不够彻底,所以还不能算是真正意义上的深拷贝,所以slice只能被称为浅拷贝;slice方法只适用于一维数组的拷贝,在二维数组中就会破绽百出;

      下面我们再来看一下二维数组的例子:

var arr1=[1,2,3,['1','2','3']];
var arr2=arr1.slice(0);
arr1[3][0]=0;
console.log(arr1);//[1,2,3,['0','2','3']]
console.log(arr2);//[1,2,3,['0','2','3']]

       上述代码是一个二维数组,当我们在arr1[3][0]里面进行更改arr1的值的时候,我们发现arr1、arr2两个数组的值都发生了变化;所以事实证明slice不是深拷贝;

      concat:

var arr1 = ['red','green'];
var arr2 = arr1.concat();//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//["red", "green"]
console.log(arr1)//["red", "green", "black"]
var arr1=[1,2,3,['1','2','3']];
var arr2=arr1.concat();
arr1[3][0]=0;
console.log(arr1);//[1,2,3,['0','2','3']]
console.log(arr2);//[1,2,3,['0','2','3']]

      

       concat方法在一维数组中是不会影响源数组的数据的,而在二维数组中concat的表现和slice是一样的;

      js的深拷贝:

      js数组中实现深拷贝的方法都多种,比如JSON.parse(JSON.stringify())和递归以及JQuery库的extend方法(只是extend方法需要依赖JQuery库,所以我们尽量的使用原生的方式来实现)都是可以实现数组和对象的深拷贝的;

var arr1 = ['red','green'];
var arr2 = JSON.parse(JSON.stringify(arr1));//复制
console.log(arr2)//['red','green'];
arr1.push('black') ;//改变color1的值
console.log(arr2)//["red", "green"]
console.log(arr1)//["red", "green", "black"]

     上述代码中我们可以清晰的看到JSON.parse(JSON.stringify())是真正意义上实现了深拷贝;

    

         递归实现深拷贝:

      

function deepClone(obj){
//判断参数是不是一个对象
let objClone = obj instanceof Object?[]:{};
if(obj && typeof obj==="object"){
for(key in obj){
if(obj.hasOwnProperty(key)){
//判断ojb子元素是否为对象,如果是,递归复制
if(obj[key]&&typeof obj[key] ==="object"){
objClone[key] = deepClone(obj[key]);
}else{
//如果不是,简单复制
objClone[key] = obj[key];
}
}
}
}
return objClone;
} var a ={
x:1,
y:2
}; b=deepClone(a);
a.x=3
console.log(a);
console.log(b);

  输出效果如下:

  

    总结:

        1:深拷贝只是从源数据中拷贝一份出来进行操作,而不是改变源数据;改变源数据的那是浅拷贝;

        2:原生js方法slice、concat都不是真正意义上的深拷贝,都仅只适用于一维数组,拷贝的属性不够彻底;

        3:实现js深拷贝我们可以通过JSON.parse(JSON.stringify())、递归以及JQuery库的extend方法来实现;

     

javascript简单实现深浅拷贝的更多相关文章

  1. Javascript 中的深浅拷贝

    工作中经常会遇到需要复制 JS 数据的时候,遇到 bug 时实在令人头疼:面试中也经常会被问到如何实现一个数据的深浅拷贝,但是你对其中的原理清晰吗?一起来看一下吧! 为什么会有深浅拷贝 想要更加透彻的 ...

  2. JavaScript中的深浅拷贝

    深浅拷贝 在JS中,数据类型分为两类: ​ 简单数据类型:Number.Boolean.String.undefined ​ 引用数据类型:Array.Object.Function 简单数据类型通常 ...

  3. Javascript 对象复制(深浅拷贝)

    一.数据类型分类: 基本变量 引用类型 二.什么叫做指针指向 栈内存.堆内存.指针指向(如下红圈圈的斜线). 三.赋值.拷贝.引用区别? 赋值指一个变量赋予某个值,包含两种方式,一种是直接量,另一种, ...

  4. 总结JavaScript对象的深浅拷贝

    十四.对象的浅拷贝与深拷贝 什么是对象的拷贝? 将一个对象赋值给另外一个对象, 我们称之为对象的拷贝 什么是深拷贝, 什么是浅拷贝? 我们假设将A对象赋值给B对象 浅拷贝是指, 修改B对象的属性和方法 ...

  5. JavaScript数据存储和深浅拷贝实际运用

    JavaScript分两种数据类型.1.简单数据类型有:number, string, boolean, undefined和null当声明一个简单数据类型的变量时,在内存中会把数据存在栈里.2.复杂 ...

  6. JavaScript中的事件委托机制跟深浅拷贝

    今天聊下JavaScript中的事件委托跟深浅拷贝 事件委托 首先呢,介绍一下事件绑定 //方法一:通过onclick <button onclick="clickEvent()&qu ...

  7. C++模板实现动态顺序表(更深层次的深浅拷贝)与基于顺序表的简单栈的实现

    前面介绍的模板有关知识大部分都是用顺序表来举例的,现在我们就专门用模板来实现顺序表,其中的很多操作都和之前没有多大区别,只是有几个比较重要的知识点需要做专门的详解. #pragma once #inc ...

  8. JavaScript深浅拷贝区别

    分享一篇自己关注的微信订阅号(前端大全)文章:JavaScript浅拷贝与深拷贝 作者:浪里行舟 https://github.com/ljianshu/Blog/issues/5 这里很详细的讲解了 ...

  9. JavaScript深浅拷贝

    深浅拷贝 基本类型和引用类型 ECMAScript 中的变量类型分为两类: 基本类型:undefined,null,布尔值(Boolean),字符串(String),数值(Number) 引用类型: ...

随机推荐

  1. 如何实现Excel多人共享与协作

    1.写在前面的话 本人从事信息化工作多年,对Excel等电子表格的多人共享与协作接触较早,帮助客户实施的方案也较多,因此有些体会和认识.正好看到网上这方面的讨论较多,但都不完整,我就进一步做了专题调研 ...

  2. javascript基本特点,组成和应用

    JavaScript 是一种基于客户端浏览器.面向(基于)对象和事件驱动式的网页脚本语言. 1. 基于客户端浏览器:静态语言,跨平台: 2. 面向(基于)对象:本身是没有类class和对象这个概念,但 ...

  3. 初识web

    人得往前走啊 所以学学web 动态网页是指在服务器端运行的,使用程序语言设计的交互式网页,它们会根据某种条件的变化,返回不同的网页内容.可以让用户和服务器交互的网站.然而动态网站并不是指具有动画功能的 ...

  4. Mybatis使用动态sql

    动态sql 常见的几种:trim.where.set.foreach.if.choose.when 下面通过案例一一演示 if语法 <select id="selectIfTest1& ...

  5. SpringBoot入门(二):日志及自定义属性

    这一章主要说springboot中日志的配置.自定义属性的配置与读取.分环境的yml配置文件(如本地环境.测试环境.生产环境等).比较偏向实际开发,较为实用,前面一章的一些基本创建在这里就不多废话了. ...

  6. Selenium模拟登陆百度贴吧

    Selenium模拟登陆百度贴吧 from selenium import webdriver from time import sleep from selenium.webdriver.commo ...

  7. 小X的逆袭

    [问题描述]毕业于普通本科的小x 一直自称是资深屌丝.谁又能想到,如此不起眼的小x 在历经重重面试环节后,竟然如愿以偿加入了心仪已久的腾讯公司!正所谓野百合也有春天,屌丝也有逆袭的那一天!一段时间以后 ...

  8. Android使用xUtils3上传图片报错解决:java.lang.ArrayIndexOutOfBoundsException: 70918

    今天在使用安卓xUtils3框架配合SmartUpload框架上传图片到Java服务端时,遇到了一个莫名其妙的错误: 安卓端代码如下: 似乎并没有发现什么问题,以前在用xUtils2.6老版本时也是这 ...

  9. java封装 redis 操作 对象,list集合 ,json串

    /** * 功能说明: * 功能作者: * 创建日期: * 版权归属:每特教育|蚂蚁课堂所有 www.itmayiedu.com */package com.redis.service; import ...

  10. Linux(CentOS7)下RabbitMQ下载安装教程

    原文链接:http://www.studyshare.cn/software/details/1172/0 一.下载安装步骤 下载erlang 1.wget 下载地址 2.rpm -Uvh erlan ...