由于自己是野生程序员,在刚开始学习程序设计的时候没有在意内存这些基础知识,导致后来在提到“什么什么是存在栈中的,栈中只是存了一个引用”这样的话时总是一脸懵逼。。
后来渐渐的了解了一些内存的知识,这部分还是非常有必要了解的。
基本数据结构
栈
栈,只允许在一段进行插入或者删除操作的线性表,是一种先进后出的数据结构。
堆
堆是基于散列算法的数据结构。
队列
队列是一种先进先出(FIFO)的数据结构。
JavaScript中数据类型的存储
JavaScript中将数据类型分为基本数据类型和引用数据类型,它们其中有一个区别就是存储的位置不同。
基本数据类型
我们都知道JavaScript中的基本数据类型有:
基本数据类型都是一些简单的数据段,它们是存储在栈内存中。
引用数据类型
JavaScript中的引用数据类型有:
引用数据类型是保存在堆内存中的,然后再栈内存中保存一个对堆内存中实际对象的引用。所以,JavaScript中对引用数据类型的操作都是操作对象的引用而不是实际的对象。
可以理解为,栈内存中保存了一个地址,这个地址和堆内存中的实际值是相关的。
图解
现在,我们声明几个变量试试:
var name="axuebin"; var age=25; var job; var arr=[1,2,3]; var obj={age:25};
可以通过下图来表示数据类型在内存中的存储情况:
此时name,age,job三种基本数据类型是直接存在栈内存中的,而arr,obj在栈内存中只是存了一个地址来表示对堆内存中的引用。
复制
基本数据类型
对于基本数据类型,如果进行复制,系统会自动为新的变量在栈内存中分配一个新值,很容易理解。
引用数据类型
如果对于数组、对象这样的引用数据类型而言,复制的时候就会有所区别了:
系统也会自动为新的变量在栈内存中分配一个值,但这个值仅仅是一个地址。也就是说,复制出来的变量和原有的变量具有相同的地址值,指向堆内存中的同一个对象。
如果所示,执行了var objCopy=obj之后,obj和objCopy具有相同的地址值,执行堆内存中的同一个实际对象。
这有什么不同呢?
当我修改obj或objCopy时,都会引起另一个变量的改变。
为什么?
为什么基础数据类型存在栈中,而引用数据类型存在堆中呢?
参考文章
理解js内存分配
原始值和引用值
在ECMAScript中,变量可以存放两种类型的值,即原始值和引用值。
原始值指的就是代表原始数据类型(基本数据类型)的值,即Undefined,Null,Number,String,Boolean类型所表示的值。
引用值指的就是复合数据类型的值,即Object,Function,Array,以及自定义对象,等等
栈和堆
与原始值与引用值对应存在两种结构的内存即栈和堆
栈是一种后进先出的数据结构,在javascript中可以通过Array来模拟栈的行为
原始值是存储在栈中的简单数据,也就是说,他们的值直接存储在变量访问的位置。
堆是基于散列算法的数据结构,在javascript中,引用值是存放在堆中的。
引用值是存储在堆中的对象,也就是说,存储在变量处的值(即指向对象的变量,存储在栈中)是一个指针,指向存储在堆中的实际对象.
例:var obj = new Object(); obj存储在栈中它指向于new Object()这个对象,而new Object()是存放在堆中的。
那为什么引用值要放在堆中,而原始值要放在栈中,不都是在内存中吗,为什么不放在一起呢?那接下来,让我们来探索问题的答案!
首先,我们来看一下代码:
function Person(id,name,age){ this.id = id; this.name = name; this.age = age; } var num = 10; var bol = true; var str = "abc"; var obj = new Object(); var arr = ['a','b','c']; var person = new Person(100,"笨蛋的座右铭",25);
然后我们来看一下内存分析图:
变量num,bol,str为基本数据类型,它们的值,直接存放在栈中,obj,person,arr为复合数据类型,他们的引用变量存储在栈中,指向于存储在堆中的实际对象。
由上图可知,我们无法直接操纵堆中的数据,也就是说我们无法直接操纵对象,但我们可以通过栈中对对象的引用来操作对象,就像我们通过遥控机操作电视机一样,区别在于这个电视机本身并没有控制按钮。
现在让我们来回答为什么引用值要放在堆中,而原始值要放在栈中的问题:
记住一句话:能量是守衡的,无非是时间换空间,空间换时间的问题
堆比栈大,栈比堆的运算速度快,对象是一个复杂的结构,并且可以自由扩展,如:数组可以无限扩充,对象可以自由添加属性。将他们放在堆中是为了不影响栈的效率。而是通过引用的方式查找到堆中的实际对象再进行操作。相对于简单数据类型而言,简单数据类型就比较稳定,并且它只占据很小的内存。不将简单数据类型放在堆是因为通过引用到堆中查找实际对象是要花费时间的,而这个综合成本远大于直接从栈中取得实际值的成本。所以简单数据类型的值直接存放在栈中。
JavaScript是脚本语言 计算机语言可以分为三类,机器语言、汇编语言、高级语言。高级语言又可以简单分为解释类和编译类。这个知道就够了。 - 机器语言: 计算机所能识别的二进制语言,一般也不会直接拿来用于编程,无法理解且难以记忆 - 汇编语言: 底层程序可以直接理解的指令,一般是英文缩写,一般简短、简单(功能简单),只能做一些非常细微的操作,复杂的操作往往伴随着大量的指令,我等一般接触不多 -
数值转换 有3种方法可以将非数值转换为数值:Number()、parseInt()、parseFloat()。 第一个函数即转型函数Number()可用于任何数据类型,而parseInt()、parseFloat()用于字符串转换为数值,一般parseInt()是将字符串转换成整数,而parseFloat()是将字符串转换成浮点型。 Number() 转换函数的规则如下: 1、如果是Boolean
JavaScript有5种基本的数据类型,分别是:undefined、null、Boolean、Number、String,还有引用数据类型object。 typeof() 由于JavaScript是松散类型的,一个变量可以存放不同类型的数据,因此需要一种方法来检验该变量属性哪种数据类型,typeof()操作符可以检测某个变量属性哪种数据类型。 typeof()可以返回的数据类型有: undefi
函数 type 能够返回一个值或一个变量所属的类型。 print(type("hello world")) -->output:string print(type(print)) -->output:function print(type(true)) -->output:boolean print(type(360.0)) -->output:n
为了让程序更易用,我们兼容几种最基本的数据类型:numbers(数字),strings(字符串),structures(结构),boolean(布尔值)等等。在 TypeScript 中,我们支持和 Javascript 几乎一样多的类型,并且新增了实用的枚举类型。 Boolean 布尔值 最基础的数据类型就是简单的 true(真)/false(假) ,在 Javascript 和 TypeScr
在 C# 中,变量分为以下几种类型: 值类型(Value types) 引用类型(Reference types) 指针类型(Pointer types) 值类型 值类型变量可以直接分配给其一个值。它们是从类 System.ValueType 中派生的。 值类型直接包含数据。比如 int、char、float,它们分别存储数字、字母和浮点数。当您声明一个 int 类型的变量时,系统将会分配内存来存
本文向大家介绍Javascript基础教程之数据类型 (数值 Number),包括了Javascript基础教程之数据类型 (数值 Number)的使用技巧和注意事项,需要的朋友参考一下 javascript中想限定一个数的数值,无需限定它是整数还是浮点数型 toExponential()函数是将数值转换为科学技术的方式显示,例如: 转下w3cschool数值的的对象属性和对象方法 Number
本文向大家介绍Javascript基础教程之数据类型转换,包括了Javascript基础教程之数据类型转换的使用技巧和注意事项,需要的朋友参考一下 所有语言都有类型转化的能力,javascript也不例外,它也为开发者提供了大量的类型转化访法,通过全局函数,可以实现更为复杂的数据类型。 最简单的类型转化的例子 对于数据类型转为字符串,使用toString() JavaScript转化为字符串同时