JavaScript中的浅拷贝与深拷贝
  学了这么长时间的JavaScript想必大家对浅拷贝和深拷贝还不太熟悉吧,今天在项目中既然用到了,早晚也要理清一下思路了,在了解之前,我们还是先从JavaScript的数据类型存放的位置 堆栈开始说起吧!           

现在我们带着问题来学习!

一:什么是堆栈?

  我们都知道:在计算机领域中,堆栈是两种数据结构,它们只能在一端(称为栈顶(top))对数据项进行插入和删除。

堆:队列优先,先进先出;由操作系统自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
栈:先进后出;动态分配的空间 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收,分配方式倒是类似于链表。
以上都属于计算机基础部分,在此都不详细赘述了,下面我们联系JavaScript来剖析一下堆栈。
二:JavaScript中的基本类型和引用类型与堆栈有什么联系?
JavaScript的数据类型分为两大种:
1. 基本类型Undefined、Null、Boolean、Number 和 String,这5中基本数据类型可以直接访问,他们是按照值进行分配的,存放在栈(stack)内存中的简单数据段,数据大小确定,内存空间大小可以分配。
2. 引用类型:即存放在堆(heap)内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。
  以上我们知道了什么是堆栈,和JavaScript的数据类型,下面我们根据js的数据类型来说明一下他们的拷贝情况:

var obj1 = {name:'bangbang',age:18};
var b = obj1;
var c = obj1.age; console.log(b.name); //bangbang
console.log(c); //
//改变b和c的值
b.name = 'yanniu';
c = 22;
console.log(obj1.name); //yanniu
console.log(obj1.age); //

 以上看出:当我们改变b的数据的时候,我们看到了obj1.name的数据也在改变,但是我们改变c的数据的时候发现,obj1.age的值没有变化,这说明了:b和obj1变量操作的是同一个对象,c和obj1完全独立的。图示如下:

三:什么是浅拷贝?
  根据上面的陈述,基本类型拷贝的时候只是在内存中又开辟了新的空间,和它的父元素(再次我们称被拷贝的对象为父元素)属于 互不想干的东西,因此深浅拷贝是相对于引用类型的,以便于我们对引用类型父对象的保存! 嘿嘿!我们接着看!
例如:

var father1 = {name:'shangdi',age:1000,job:['teacher','cook']};
//浅拷贝函数
function copy(obj){
var childs = {};
for(var key in obj){
childs[key] = obj[key];
}
return childs;
}
var child1 = copy(father1);
console.log(child1); //{ name: 'shangdi', age: 1000 }
console.log(typeof child1); //object //改变子对象的name属性,发现对父对象的name没有影响 哈哈!
child1.name = 'bangbang';
console.log(father1); //{ name: 'shangdi', age: 1000 }
console.log(child1); //{ name: 'bangbang', age: 1000 } //注意:这次改变子对象的job属性也就是改变数组,
//发现对父对象的job竟然有影响,吓死宝宝了,那怎么办呢,那这个copy有什么用呢是吧!
child1.job.push('programer');
console.log(father1); //{ name: 'shangdi',age: 1000,job: [ 'teacher', 'cook', 'programer' ] }
console.log(child1); //{ name: 'shangdi',age: 1000,job: [ 'teacher', 'cook', 'programer' ] }

由上面可分析:浅拷贝的时候,当我们改变子对象的数组的时候,父对象竟然也跟着改变,也就是说:子对象和父对象在浅拷贝的时候他们指向同一个内存的数组:由图所示:

如果我们想让子对象的拷贝和父对象没有一点关联,那么我们就必须用到深度拷贝!嘿嘿!儿子也不能完全跟着爹长啊!

四:什么是深度拷贝?
深度拷贝就是把父对象拷贝到子对象上,而且两者的内存和以后的操作都互不影响的拷贝!

function deepCopy(obj){
var o;
switch(typeof obj){
case 'undefined': break;
case 'string' : o = obj + '';break;
case 'number' : o = obj - 0;break;
case 'boolean' : o = obj;break;
case 'object' :
if(obj === null){
o = null;
}else{
if(obj instanceof Array){
o = [];
for(var i = 0, len = obj.length; i < len; i++){
o.push(deepCopy(obj[i]));
}
}else{
o = {};
for(var k in obj){
o[k] = deepCopy(obj[k]);
}
}
}
break;
default: o = obj;break;
}
return o;
}

下面是一些克隆的方法供大家参考,不过他们有区别,自己试验:
方法二:最简单的

function deepCopy(obj) {
return JSON.parse(JSON.stringify(obj));
}

方法三:

function deepCopy(obj){
var newobj, obj;
if (obj.constructor == Object){
newobj = new obj.constructor();
}else{
newobj = new obj.constructor(obj.valueOf());//valueOf()方法返回 Array 对象的原始值
}
for(var key in obj){
if ( newobj[key] != obj[key] ){
if ( typeof(obj[key]) == 'object' ){
newobj[key] = deepCopy(obj[key]);
}else{
newobj[key] = obj[key];
}
}
}
newobj.toString = obj.toString;
newobj.valueOf = obj.valueOf;
return newobj;
}

方法四:

var cloneObj = function(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== 'object'){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //系列化对象
newobj = JSON.parse(str); //还原
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === 'object' ?
cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};

方法五:(JavaScript面向对象编程指南)

function deepCopy(p,c){
c = c || {};
for (var i in p){
if(p.hasOwnProperty(i)){
if(typeof p[i] === 'object'){
c[i] = Array.isArray(p[i]) ? [] : {};
deepCopy(p[i],c[i]);
}else{
c[i] = p[i];
}
}
}
return
}
原文来自:https://blog.csdn.net/flyingpig2016/article/details/52895620
 

深入理解JavaScript中的堆与栈 、浅拷贝与深拷贝的更多相关文章

  1. 理解JavaScript中的堆和栈

    这里先说两个概念:1.堆(heap)2.栈(stack)堆 是堆内存的简称.栈 是栈内存的简称.说到堆栈,我们讲的就是内存的使用和分配了,没有寄存器的事,也没有硬盘的事.各种语言在处理堆栈的原理上都大 ...

  2. 设计模式之原型模式(深入理解OC中的NSCopying协议以及浅拷贝、深拷贝)

    原型模式:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.原型模式其实就是从一个对象再创建另一个可定制的对象,而且不需知道任何创建的细节. 比如说,有一个Person类,有firstN ...

  3. JavaScript 数据结构与算法之美 - 栈内存与堆内存 、浅拷贝与深拷贝

    前言 想写好前端,先练好内功. 栈内存与堆内存 .浅拷贝与深拷贝,可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法之美 系列用的语言是 JavaScri ...

  4. 栈 堆 stack heap 堆内存 栈内存 内存分配中的堆和栈 掌握堆内存的权柄就是返回的指针 栈是面向线程的而堆是面向进程的。 new/delete and malloc/ free 指针与内存模型

    小结: 1.栈内存 为什么快? Due to this nature, the process of storing and retrieving data from the stack is ver ...

  5. Java中的堆和栈的区别

    当一个人开始学习Java或者其他编程语言的时候,会接触到堆和栈,由于一开始没有明确清晰的说明解释,很多人会产生很多疑问,什么是堆,什么是栈,堆和栈有什么区别?更糟糕的是,Java中存在栈这样一个后进先 ...

  6. java中的堆、栈、常量池

    java中的堆.栈.常量池 分类: java2010-01-15 03:03 4248人阅读 评论(5) 收藏 举报 javastring编译器jvm存储equals Java内存分配: 1. 寄存器 ...

  7. 理解 JavaScript 中的 this

    前言 理解this是我们要深入理解 JavaScript 中必不可少的一个步骤,同时只有理解了 this,你才能更加清晰地写出与自己预期一致的 JavaScript 代码. 本文是这系列的第三篇,往期 ...

  8. java中的堆与栈

    Java 中的堆和栈 Java把内存划分成两种:一种是栈内存,一种是堆内存. 在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配 . 当在一段代码块定义一个变量时,Java就在栈中 ...

  9. 理解JavaScript中的原型继承(2)

    两年前在我学习JavaScript的时候我就写过两篇关于原型继承的博客: 理解JavaScript中原型继承 JavaScript中的原型继承 这两篇博客讲的都是原型的使用,其中一篇还有我学习时的错误 ...

随机推荐

  1. c#百度IP定位API使用方法

    c#百度IP定位API使用方法 1.先建立一个收集信息的实体类 IPModel.cs: using System; using System.Collections.Generic; using Sy ...

  2. JMeter-完成批量的接口测试

    前言 当我们在工作中进行接口测试时,项目的接口肯定不止一个,而是很多很多,而且每个接口都需要进行正确参数,错误参数,参数为空,特殊字符等方式来测试接口是否能够正确返回所需的响应值. 今天,我们来一起学 ...

  3. 字符串匹配算法 之BF、KMP

    示例: 1. 已知字符串str1="acabaabaabcacaabc",求str2="abaabcac"是否在字符串str1中? 2. DNA病毒检测.已知患 ...

  4. 正式学习MVC 04

    1.ActionResult ActionResult是一个父类, 子类包括了我们熟知的 ViewResult 返回相应的视图 ContentResult  返回字符串 RedirectResult( ...

  5. 【布局】圣杯布局&双飞翼布局

    背景 随着前端技术的发展推进,web端的布局方式已基本成熟,那么在网站布局方式中,三列布局最为常用,布局方式也有很多,渐渐的开发者们开始从效率的角度优化自己的代码"如果三排布局能将中间的模块 ...

  6. css实战#用css画一个中国结

    大家好!今天跟大家分享一个用 css 画中国结的教程.最终效果如下: 大家如果感兴趣可以参考我的源码:gitHub地址 首先,我们定义好画中国结需要的结构: <div class="k ...

  7. apache搭建Tomcat集群(Cluster)

    搭建集群: apache:特点处理静态资源(html  图片  js等) apache的请求操作,Cluster工具 tomcat:特点处理动态资源 apache+tomcat(apache是web服 ...

  8. 20 本地SQL查询

    Spring Data JPA同样也支持sql语句的查询 //nativeQuery : 使用本地sql的方式查询 @Query(value="select * from customer& ...

  9. php获取当前周的第一天与最后一天

    1 2 3 4 5 6 7 8 9 10 // 当前日期   $sdefaultDate = date("Y-m-d");   // $first =1 表示每周星期一为开始日期  ...

  10. go中处理各种请求方式以及处理接口请求参数

    话不多说直接上代码,解读内容全部在代码中 1.处理请求方式 package main import ( "fmt" "io/ioutil" "net/ ...