一.堆栈的定义

1.栈是一种特殊的线性表。其特殊性在于限定插入和删除数据元素的操作只能在线性表的一端进行。

结论:后进先出(Last In First Out),简称为LIFO线性表。栈的应用有:数制转换,语法词法分析,表达式求值等

2.队列(Queue)也是一种运算受限的线性表,它的运算限制与栈不同,是两头都有限制,插入只能在表的一端进行(只进不出),而删除只能在表的另一端进行(只出不进),允许删除的一端称为队尾(rear),允许插入的一端称为队头 (Front),队列的操作原则是先进先出的,所以队列又称作FIFO表(First In First Out)。

由于栈和队列也是线性表,栈和队列有顺序栈和链栈两种存储结构,这两种存储结构的不同,则使得实现栈的基本运算的算法也有所不同。

二.JS堆栈研究

1、栈(stack)和堆(heap)

stack为自动分配的内存空间,它由系统自动释放;而heap则是动态分配的内存,大小不定也不会自动释放。

2、基本类型和引用类型

(1) 基本类型 :存放在栈内存中的简单数据段,数据大小确定,内存空间大小可以分配。

5种基本数据类型有Undefined、Null、Boolean、Number 和 String,它们是直接按值存放的,所以可以直接访问。

(2) 引用类型 :存放在堆内存中的对象,变量实际保存的是一个指针,这个指针指向另一个位置。每个空间大小不一样,要根据情况开进行特定的分配。

当我们需要访问引用类型(如对象,数组,函数等)的值时,首先从栈中获得该对象的地址指针,然后再从堆内存中取得所需的数据。

3、传值与传址

前面之所以要说明什么是内存中的堆、栈以及变量类型,实际上是为了更好的理解什么是“浅拷贝”和“深拷贝”。

基本类型与引用类型最大的区别实际就是传值与传址的区别。测试用例:
var a = [,,,,];
var b = a;
var c = a[];
alert(b);//1,2,3,4,5
alert(c);//1 //改变数值
b[] = ;
c = ;
alert(a[]);//
alert(a[]);//

从上面我们可以得知,当我改变b中的数据时,a中数据也发生了变化;但是当我改变c的数据值时,a却没有发生改变。这就是传值与传址的区别。因为a是数组,属于引用类型,所以它赋予给b的时候传的是栈中的地址(相当于新建了一个不同名“指针”),而不是堆内存中的对象。而c仅仅是从a堆内存中获取的一个数据值,并保存在栈中。所以b修改的时候,会根据地址回到a堆中修改,c则直接在栈中修改,并且不能指向a堆内存中。

三.拷贝

1.浅拷贝

前面已经提到,在定义一个对象或数组时,变量存放的往往只是一个地址。当我们使用对象拷贝时,如果属性是对象或数组时,这时候我们传递的也只是一个地址。因此子对象在访问该属性时,会根据地址回溯到父对象指向的堆内存中,即父子对象发生了关联,两者的属性值会指向同一内存空间。

var a = {
key1:""
}
function Copy(p) {var c = {};
for (var i in p) {
c[i] = p[i];
}
return c;
}
a.key2 = ['小辉','小辉'];
var b = Copy(a);
b.key3 = '';
alert(b.key1); //
alert(b.key3); //
alert(a.key3); //undefined

a对象中key1属性是字符串,key2属性是数组。a拷贝到b,12属性均顺利拷贝。给b对象新增一个字符串类型的属性key3时,b能正常修改,而a中无定义。说明子对象的key3(基本类型)并没有关联到父对象中,所以undefined。

b.key2.push("大辉");
alert(b.key2); //小辉,小辉,大辉
alert(a.key2); //小辉,小辉,大辉

但是,若修改的属性变为对象或数组时,那么父子对象之间就会发生关联。从以上弹出结果可知,我对b对象进行修改,a、b的key2属性值(数组)均发生了改变。其在内存的状态,可以用下图来表示。

原因是key1的值属于基本类型,所以拷贝的时候传递的就是该数据段;但是key2的值是堆内存中的对象,所以key2在拷贝的时候传递的是指向key2对象的地址,无论复制多少个key2,其值始终是指向父对象的key2对象的内存空间。

2.深度拷贝

或许以上并不是我们在实际编码中想要的结果,我们不希望父子对象之间产生关联,那么这时候可以用到深拷贝。既然属性值类型是数组和或象时只会传址,那么我们就用递归来解决这个问题,把父对象中所有属于对象的属性类型都遍历赋给子对象即可。测试代码如下:

function Copy(p, c) {var c = c || {};
for (var i in p) {
if (typeof p[i] === 'object') {
c[i] = (p[i].constructor === Array) ? [] : {};
Copy(p[i], c[i]);
} else {
c[i] = p[i];
}
}
return c;
}
a.key2 = ['小辉','小辉'];
var b={};
b = Copy(a,b);
b.key2.push("大辉");
alert(b.key2); //小辉,小辉,大辉 alert(a.key2); //小辉,小辉

由上可知,修改b的key2数组时,没有使a父对象中的key2数组新增一个值,即子对象没有影响到父对象a中的key2。其存储模式大致如下:

 
 参考:http://www.tuicool.com/articles/EviuUfV
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

JS堆栈与拷贝的更多相关文章

  1. 关于JS堆栈与拷贝

    1.栈(stack)和堆(heap) stack为自动分配的内存空间,它由系统自动释放:而heap则是动态分配的内存,大小不定也不会自动释放. 2.基本类型和引用类型 基本类型:存放在栈内存中的简单数 ...

  2. JS对象的拷贝

    1:对数据进行备份的时候,如果这个数据是基本的数据类型,那么很好办,通过赋值实现复制即可. 赋值与浅拷贝的区别 var obj1 = { 'name' : 'zhangsan', 'age' : '1 ...

  3. js 数组的拷贝

    在js中,数组Array是引用类型,直接将数组赋值给一个变量名,二者所指向的地址是一样的. 所以直接复制数组会产生意想不到的结构. 要想解决拷贝一个数组但是对副本的修改不影响原来的数组,有以下方式: ...

  4. JS中深浅拷贝 函数封装代码

    一.了解 基本数据类型保存在栈内存中,按值访问,引用数据类型保存在堆内存中,按址访问. 二.浅拷贝 浅拷贝只是复制了指向某个对象的指针,而不是复制对象本身,新旧对象其实是同一内存地址的数据,修改其中一 ...

  5. js堆栈与队列简单记忆

    在面向对象的程序设计里,一般都提供了实现队列(queue)和堆栈(stack)的方法,而对于JS来说,我们可以实现数组的相关操作,来实现队列和堆栈的功能,看下面的相关介绍. 一 看一下它们的性质,这种 ...

  6. js堆栈内存的释放

    ### JS中的堆栈内存 > 俗称叫做作用域(全局作用域/私有作用域) > - 为js代码提供执行的环境(执行js代码的地方) > - 基本数据类型值是直接存放在栈内存中的 > ...

  7. js实现深度拷贝

    js实现拷贝,使用普通赋值对象,在操作其中一个对象值的时候,另一个也会更改,不符合需求 因此引入深度拷贝,以下为实现深度拷贝的几种法: Object.assign // 合并多个对象 var targ ...

  8. js堆栈溢出错误

    function prompt() { var answer = prompt("What is your name","") if (answer) { al ...

  9. js学习笔记<拷贝传值,引用传址和匿名函数>

    拷贝传值:把一个变量的值拷贝一份,传给了另外一个变量拷贝传值中,两个变量之间没有任何联系,修改其中一个一个变量的值,原来的变量不变. 例: var arr1 = ["张三",24, ...

随机推荐

  1. docker--命令详解

    查看版本: docker --version 查看docker信息: docker info 进入容器: docker exec -it bb /bin/bash #在容器中执行一个bash可以操作容 ...

  2. LAMP和LNMP去除index.php访问

    使用TP或者Laravel开发的时候,后时候会遇到需要加index.php才能正常访问 LAMP解决方法 1.修改配置 打开配置文件(如:httpd.conf),找到你网站根目录的配置,将AllowO ...

  3. 概率dp总结 正在更新

    借bin神一句话 概率DP主要用于求解期望.概率等题目. 转移方程有时候比较灵活. 一般求概率是正推,求期望是逆推.通过题目可以体会到这点. 先推公式 多个 -> 一个 明确dp[i]代表什么意 ...

  4. Codeforces Round #426 (Div. 2) A,B,C

    A. The Useless Toy 题目链接:http://codeforces.com/contest/834/problem/A 思路: 水题 实现代码: #include<bits/st ...

  5. Cuba获取属性文件中的配置

    最直接的办法是,使用AppContext.getProperty("cuba.trustedClientPassword"); 可以获取到系统中的web模块下的wep-app.pr ...

  6. LOJ #6202. 叶氏筛法(min_25 筛)

    题意 求 \([L, R]\) 之间的素数之和 . \(L≤10^{10},2×10^{10} \le R \le 10^{11}\) 题解 一个有点裸的 min_25筛 ? 现在我只会筛素数的前缀和 ...

  7. 自学Python1.4-Centos内vim中文乱码问题

    自学Python之路 自学Python1.4-Centos内vim中文乱码问题 1. 登陆的系统---区域语言设置 1.1查看安装中文包: 查看系统是否安装中文语言包 (列出所有可用的公共语言环境的名 ...

  8. SP1805 HISTOGRA (单调栈)

    单调栈维护栈顶为高度最大的 记下来栈中每个元素入栈时顶掉的最靠左的一个位置(如果没顶掉就是它本身),那么在它出栈的时候,它所带来的面积就是(出栈位置-记录位置)*高度 (可能会有加一减一之类的细节) ...

  9. HTMLUnit web测试

    httpClient不能动态执行网页中的js,这样无法获取js生成的动态网页.htmlUnit是个解决方法. if you’re considering web application testing ...

  10. Luogu 1315 【NOIP2011】观光公交 (贪心)

    Luogu 1315 [NOIP2011]观光公交 (贪心) Description 风景迷人的小城Y 市,拥有n 个美丽的景点.由于慕名而来的游客越来越多,Y 市特意安排了一辆观光公交车,为游客提供 ...