数据类型

基本类型、引用类型

   系统总结Javascript语言所有类型之前,先来理解数据类型与内存的联系。内存毫无疑问是用来存储数据的,一般这些数据可以分为数据和数据的地址, 当然数据的地址本质上 也是数据,你可以把数据的地址成为指针。 比如在函数中声明一个数字变量let a = 10;数字10在代码初始化分配 内存的时候 会存储在栈内存,在这句代码之后在执行let b = a,栈内存会重新开辟一个位置存储变量b,把a的值赋值给b,注意不是变量 a的地址。 这种内存特征的的数据属于基本类型。函数中定义一个对象let a = { }或数组,let a = [ ],会在栈内存分配空间用来存储 数组或对象的数据,变量保存的实际上是一个指针, 指向对象或数组存储地址,类似这种内存特点的数组称为引用类型,顾名思义引用 数据,而不是复制数据。在代码let a = [ ]之后执行let b = a,数组a的数据不会复制到数组b, 执行b = a,变量b得到的是数组a的数据地址,这个时候变量名b和a一样同时指向栈内存中的数据块,通过a[]或b[]都可以修改或者引用它们指向的数组数据。

   ES5标准中Javascript有六种数据类型,布尔Boolean、空Null、未定义Undefined、数字Number、字符串String和Object, ES6新增一种数据类型Symbol。 除了Object数据类型外,都属于原始类型数据,也可以称为值类型、基本类型、基础类型, Object数据类型称为引用类型,比如数组、自定义的对象、函数。可有有些读者会问 不是万物皆对象吗,字符串也具有 方法和属性,为什么不是Object类型。可以这样去思考,所有的数据都是对象,只是数字、字符串和自定义的对象不同, 可以理解为特殊的专用对象, 有自己的内存分配管理规则。 可能会有很多的教程说“对象”是Object类型的数据,这里所说的“对象”是有特指的,所以上面我强调自定义的对象 ,比如通过通过大括号{ }或new创建的对象。

数据类型 意义 应用场景
Boolean 仅true和false if(true)执行,if(false)不执行 if(a == 0)
Null 仅null, 空指针常量,用于解除索引,方便内存管理 let a ={...}; let a = null;
Undefined 仅undefined 声明变量的时候,变量没有赋值,初始化时变量默认值undefined
Number 2、2.3、5.0等等 let a = 2*3
String " "
Object { }、[ ]

数字类型

 整型、浮点型数据识别

   在C语言中不同的数据类型在内存中存储的格式不同,标识方法不同,数据类型往往反映的是一个数值变量站的内存单元大小, 比如在C语言中int整型数占32位,float单精度浮点数32位,double双精度浮点数64位。 Javascript语言没有设置int、float、double等关键字区分数字的类型,声明变量不会定义数据类型。 Javascript语言虽然没有声明一个数据的类型,但是不代表Javascript解释器不识别。一般在变量赋值的时候写5,就会按照整型的的格式存储,赋值的时候写5.1,就会按照 浮点型的格式存储。整型数据赋值除了用5、16等十进制形式,也可以用十六进制,用0x标识,比如0x12BF,也可以用二进制形式,用0b标识,比如0b011; Javascript采用IEEE754标准定义格式表示整数和浮点数,Javascript浮点数和C语言中的双精度浮点数一样每个数字占内存单元64位,浏览器存储Javascript整数采用32位, 浮点数格式相比整数更占用内存,比如浮点数5.0和整数5数值是一样的,Javascript解释器会不失时机把5.0这种浮点数值转化为整数值。

 浮点数精度

   计算机的数字电路使用高低电平两个状态来表达数学的二进制,过去技术有限,数字电路两个状态好控制,现在的技术实现数字电路实现10个稳定电压状态不难,所以说10进制计算机也可以存在, 这都是硬件工程师创新的事情,软件工程师不必太关心,主要关心硬件资源有限,引发的数字存储精度问题。 人类社会不同的民族不同年代也有不同的进制,有主流的10进制,也有非主流的5进制、20进制。不论哪种进制在表达世界的时候都会存在无限循环小数,但是计算机的存储资源 是有限的,也就是说要控制小数有效数字的位数,在保留有效数字的过程中,必然出现数据保存运算误差。浮点数的乘法运算相比加减法运算误差更明显。

十进制整数10的二进制形式是1010,在内存中效果如下(分配32位内存空间),

00000000 00000000 00000000 0000 1010

正整数、负整数、浮点数都有自己的存储方式,不同的语言、标准、平台都会有所差异,这里不再详述

  执行代码document.write(0.1+0.2);,在网页上显示的结果并不是0.3,而是0.30000000000000004,同样0.1+0.2 == 0.3的返回值也是是false. 主要是因为浏览器加载html或js文件解析代码初始化的时候, 十进制的浮点数0.1、0.2会以二进制的形式存储在动态内存中,可以查看下表十进制的0.1和0.2对应的二进制小数都是无限循环小数,表示原始数据和相加的结果只能保留有限的有效数字。

分数 十进制小数 二进制小数
1/2 0.5 0.1
1/4 0.25 0.01
1/8 0.125 0.001
1/5 0.2 0.0011001100110011(无限循环小数)
1/10 0.1 0.0001100110011001(无限循环小数)
1/3 0.3333333333333333(无限循环小数) 0.0101010101010101(无限循环小数)

 科学计数法

字符串类型

   字符串与数字类型一样都属于原始类型数据,不同的地方就是字符串占据的内存的长度是不固定的,字符越多需要的内存越多, 而浮点数不管大小都是占据固定的内存长度64位。Javascript一般提供内置的构造函数String,使用操作符new和String也可以创建字符串。 比如下面代码
var a = '承炎黄血脉';
var b = new String('扬华夏科技');
  这时候变量a相当于原始类型数据,字符串“承炎黄血脉”存储在栈内存,变量b相当于引用数据,字符串“扬华夏科技”存储在堆内存,数据的指针赋值给变量b。 原始类型字符串对象和引用类型字符串对象都拥有Javascript内置字符串的属性和方法,比如length。使用构造函数String创建的字符串对象可以通过点运算符 增加新的自定义属性和方法,使用引号创建的字符串支持Javascript内置的字符串对象属性和方法,不支持自定义添加方法和属性。如果不使用new直接调用函数String()创建字符串返回的数据是原始类型,与使用 引号创建字符串产生的数据类型一样,前面说过关键字new有开辟内存的作用。

“+”运算

  字符串是由一系列符号构成,和数组类比把每一个符号都是为一个元素,比如字符串str = "我们的征途是星辰大海" ,每一个汉字字符都是一个元素,执行str.length返回的个数就是元素个数,也就是汉字的个数, 注意不是占据的内存字节或位数,str2 = "abs123$!"里面的英文字母、美元符号、阿拉伯数字都是一个元素,一个英文字母和一个汉字在元素数量统计上没什么不同,区别在于 在内存上分配的空间根据不同的编码方法会有所差异,按照UTF-8标准,一般一个汉字3个字节或4个字节但,一个数字和一个英文字母都是占用一个字节。 字符串的每一个元素会分配一个索引地址,第一个元素是0的二进制形式,第二个是1的二进制形式,以此类推,不过字符串不能像数组一样利用下标更改具体元素值,不过字符串支持 两个字符串执行+运算会得到一个新的字符串,比如str1 = "我们的征途";str2 = "是星辰大海" ;str3 = str1+ str2的返回值是"我们的征途是星辰大海", str3得到的是str1和str2字符串的内容而不是字符串的索引。

数据类型隐式转换

  比如字符串和数字执行“+”运算,3+"abc",数字类型的数据3会自动转化为字符串类型,不需要程序员使用数字类型对象的方法toString()手动变换数字类型为字符串类型,解释器在 解释、编译的时候会自动转化,比如数字5是数字类型的时候占64位(八个字节),而转化为字符串类型就是站8位(一个字节)。关于隐式变换和显示变换在其它课中会专门讲解。

字符串创建

Null类型

  null单词本身就是无效的意思,它可以用于解锁索引,释放内存。
let a ={};
let a = null;
语句let a ={};创建了一个对象,代码初始化就会在内存占用空间, Javascript解释器会定时检查内存中哪些对象不再被引用,零引用的对象会被清空。变量名a是新建对象的引用, 指向对象区域的指针,null是一个空指针数据,当把null赋值给变量a,变量a不再指向a对象,占用内存就会自动释放。 有兴趣可以研究内存释放的详细机制。

Undefined类型

  Undefined英文是未定义的意思,编写程序时,当声明语句let a;执行typeof a返回"undefined",也就是说 语句typeof a == "undefined"会返回true,也就是说当解释器执行到if(typeof a == "undefined"){}时候,会执行if大括号里 面的代码。当声明语句let a = 10;执行typeof a返回"number"。

Object类型

  函数、数组、对象都是引用类型,函数名、数组名、对象名都会指向函数、数组、对象数据块。不使用的引用数据, 要把他们的变量名及时赋值null。

typeof判断数据类型

   typeof关键字用来判断数据的类型,比如WebGL加载stl三维格式文件, 处理大量的数据时,一个数组里面有数字、字符串需要识别出来,这时候typeof就可以派上用场, 不同的数据有不同的内存分配、存储形式,这就是typeof能够分辨的基础,至于在硬件层面,typeof的具体运行 过程当做黑箱即可。

typeof操作符 返回结果
typeof undefined "undefined"
typeof false "boolean"
typeof "abc" "string"
typeof null "object"
typeof [] "object"
typeof {} "object"
function fun(){} typeof fun "function"

  函数属于引用类型,对函数名执行typeof操作返回"function"而不是"object",主要是为了更好的识别函数。 null执行typeof操作,返回的是"object",很好理解,null是引用数据的空指针,引用数据就是Object类型数据。