JavaScript基础之数据类型

JavaScript是脚本语言

计算机语言能够分为三类,机器语言、汇编语言、高级语言。高级语言又能够简单分为解释类和编译类。这个知道就够了。编程

机器语言: 计算机所能识别的二进制语言,通常也不会直接拿来用于编程,没法理解且难以记忆
汇编语言: 底层程序能够直接理解的指令,通常是英文缩写,通常简短、简单(功能简单),只能作一些很是细微的操做,复杂的操做每每伴随着大量的指令,我等通常接触很少
高级语言: 简单理解,咱们日常接触到的据说过的基本都是高级语言。高级语言又分为解释类和编译类。解释类语言和编译类语言都须要转换成机器语言才能被机器执行,区别在于转换的时间,解释类语言也就是通常通称的脚本语言,依赖于解释器,边解释边执行,编译类是所有转换(编译)好了,打包拿出去执行。JavaScript不须要编译,可是须要在本身的解释器上执行,好比咱们经常使用的浏览器。

内存、地址、指针

有过C语言基础的人必定据说过这么一句话,指针是C语言的灵魂。可是彷佛在JavaScript中,并无接触过所谓的指针的概念,但JavaScript的解释器(JavaScript引擎)无论用什么编写,有的是C,有的是C++,也或者是Java,甚至是JavaScript自举实现的JavaScript解释器(元循环虚拟机),都逃不脱内存和指针,在JaVaScript中也有体现。因此了解下这些概念,对于学习JavaScript,总归是有好处的。浏览器

计算机内存最小单位是位,8位一个字节(byte),实际计算机中,内存最小单位是字节(byte),通俗来说,能够把内存条当作内存,计算机运行时临时存储数据的地方。也能够把它看作一个大的图书馆,有无数个格子,每一个格子都有一个编号,这个编号就是地址,每一个地址对应惟一一段内存。咱们一般所说的系统为数据分配一段内存,也就是给这个数据分配格子,一个格子放不下,那就给分三五个格子来放。而指针则是固定占用4个格子(4byte),里面放的不是真实的数据,而是放的另一段内存的地址,只是个地址。函数



原始数据类型

Undefined、Null、Boolean、Number、String和Symbol(ES6)学习

原始数据类型实在太简单,因此只简单划几个重点:指针

  • 原始数据类型不可改变 原始数据类型一个很是重要的特征就是不可改变。原始数据类型是保存在栈中的,一旦声明一个变量 var a = "老李";解释器会申请一块内存来存储"老李",a是标识符(标识符存储的是内存地址,但在通过解释/编译后会就不须要了),若是此时其余操做尝试修改a,好比a += ",你好!";,此时打印a,虽然会输出"老李,你好!";可是实际这其中改变的是a的地址指向,解释器会为"老李,你好!"申请一片新的内存来存储,a中存储的指向改变了,原先的"老李"所占用的内存会被回收但自己并未被改变。code

  • 原始数据类型是按值传递 原始数据类型的赋值,也是新开辟一片内存地址来存放新的指针和值,好比:var b = a;虽然看起来b和a同样,但实际上b和a一点点关系都没有,各自有各自的标识符和占用的内存,只是恰好值相同。ip

引用数据类型

Object
这里的Object不是狭义的Object,包含JavaScript的预约义引用类型:Object、Array、Date、Boolean、Number、String,对,这些都是引用数据类型。也就是一个数字/日期/布尔值/字符串他们的字面量声明方式和构造函数声明方式会形成彻底不同的结果。也就是上面划的两个重点,这里须要从新划一下。内存

  • 引用数据类型能够改变 我想说的不是这句废话,引用数据类型和原始数据类型存储在 栈和堆中,栈中存储的是标识符和指针,堆中存储的才是实际地址。画个表(表也懒得画了,下面的凑活看)吧:字符串

var a = 1;
var a1 = a;
var b = {value: 1};
var b1 = b;
var c = new Object(1);
var c1 = c;
var d = new Number(1);
var d1 = d;

          栈                                               堆    
a         1                                                无
a1        1(和a的1占用的不一样的内存)                          无
b         指针,{value: 1}所占的内存地址                      {value: 1}
b1        指针,指向和b相同,但指针自己存储在新的内存中           同上,且是同一块内存中的相同的值
c         指针,1所占的内存地址                               1(object)
c1        指针,1所占的内存地址,但指针自己存储在新的内存中        同上,且是同一块内存中的相同的值
d         指针,1所占的内存地址                               1(number)
d1        指针,1所占的内存地址,但指针自己存储在新的内存中        同上,且是同一块内存中的相同的值

简单讲,原始数据类型,永远是一个标识符对应一个值(一段内存)且都存放在栈里;引用数据类型永远是一个标识符对应一个指针指向同一个值(同一段内存),前两者存储在栈中,最后一个在堆中。来几个例子帮助理解下:虚拟机

var a = 1;
var a1 = a;

a1 = 2;

console.log(a, a1);      //1 2

这个很好理解你们各自有各自的标识符和内存地址,你变你的,不影响我。下一个例子:

var b = {value: 1};
var b1 = b;

b1.value = 2;

console.log(b.value, b1.value)    //2 2

也好理解,b和b1指向的是同一个东西,简单理解就是b和b1共用同一个东西。b1改完了b再来访问,拿到的确定是改后的。下一个例子:

var c = new Object(1);
var c1 = c;

c1 = 2;

console.log(c, c1)        //{[[PrimitiveValue]]: 1}  2  PrimitiveValue就是指的原始值,这里其实只是将原始值1包装成Object,而这个原始值1依然不可更改

也很简单,c1 = 2;这句话从新声明了c1,表明着指针的c1被回收了,c1被从新声明为一个原始数据类型,这时候两者不要紧了,若是是换一个方法,好比:

var c = new Object(1);
var c1 = c;

c1.value = 1;

console.log(c, c1)  //{value: 1,[[PrimitiveValue]]: 1} {value: 1,[[PrimitiveValue]]: 1}

这样就没问题了。



参数中的原始数据和引用数据

原始数据类型是按值传递的,引用数据类型是按引用传递的,看例子:

var a = 1;
var b = {value: 1};

function foo(v){
    v = "new Value";
}

foo(a);

在函数调用时,其实进行了以下操做:
将a赋值给v,也就是v = a;,建立了a的副本,此时v获得了本身的内存,其中存放着1这个值,而后拿"new Value"去覆盖1,然而这一切发生在a的副本上,和a彻底没有关系,因此此时打印出a,仍是1。接着:

foo(b);

这个结果也很好猜,b也没有变,一样建立一个副本,副本有标识符、指针,指针指向的也是b的指针指向的值,可是v = ”new Value“;执行时,这个副本就被从新赋值位一个string了,原先那个指针被回收。接着:

var a = 1;
var b = {value: 1};
var c = new Number(1);

function foo(v){
    v.value = "new Value";
}

foo(a);
foo(b);
foo(c);
  1. a依然是1,且不说原始数据不能被添加属性,即使被添加也只是a的副本的事,和a没一点关系;

  2. b在函数执行中一样建立了副本,副本一样有指针,指向了{value: 1}所在的实际地址,此时经过指针改变了存储`{value:
    1}`的内存中的value值,因此此时再经过b去访问,同样是输出改变后的值;

  3. c和b原理同样,只不过c原本没有value属性,因此会被添加一个value属性,因此上面的abc结果分别是:

console.log(a);            // 1
console.log(b);            // {value: "new Value"} 
console.log(c);            // Number {value: "new Value", [[PrimitiveValue]]: 1}
相关文章
相关标签/搜索