【JS之路】“简单”的数据类型
JavaScript数据类型
ECMAScript规定了8种数据类型,又分为两种:简单数据类型
和复杂数据类型
。
简单数据类型
-
Number
:整数或者浮点数(里面还包括一些特殊值,例如:Infinity 代表无穷大,-Infinity 代表无穷小,NaN(not a number)) -
Boolean
:只包含两个值 true和false -
字符串
:用单引号或者双引号包裹起来的都叫字符串 -
underfined
:未定义的 -
null
:空
在ES6+中加入了
Symbol
、BigInt
(本文暂不作讨论)
复杂数据类型:
-
object
:对象类型,平时用的包括Object
、Function
、Array
、Math
、Date
等都是特殊的对象。
为什么要区分简单数据类型和复杂数据类型
说简单点,相对于java、c++等高级语言一样,就是变量
和对象
的区别,这种区别是可显式的。谈及变量自然离不开内存
,今天我们主要以JavaScript为始,以内存
的存储方式来展开。
不可变性
在ECMAScript标准中,简单数据类型被定义为primitive values
,即原始数值,代表他的值是不可变的。 看到这里,肯定有读者发出疑问:JavaScript里面都是变量
啊!不能改变,那不是就成常量
了?
别急,我们从内存来逐步理解:
在JavaScript中,变量
是松散
类型的,变量可以保存任何类型的数据。简单来说,每个变量仅仅是一个占位符而已,它里面可以任意存值。
JavaScript中的内存总体分为两种:栈
内存和堆
内存
栈内存
特点:
- 存储空间的
大小
固定(即创建时的大小是确定的) - 总空间较小
- 可以直接操作变量,运行效率高(因为
JavaScript
代码是在栈区执行的) - 由编译器分配空间
而JavaScript中的简单数据类型
的值,其实就是存储在栈区
。
先看一下栈区的存储方式
下面我们通过一道简单的运算题来理解栈内存的存储模式。
var str="abc";
str=str+"d"; // "abcd"
上面代码中,我们对str
变量进行了:str+“d”,实际上是在栈中又开辟了一块内存空间用来存储新的值“abcd”
,然后将str
变量指向这块新的内存空间。但是,这并不违背不可变性
这一特点
引用对象
JavaScript中的对象其实就是一堆数据和功能的集合,算是一种数据结构。我们在这里说一下复杂数据类型
在内存的存储方式,也就是堆
内存。
堆内存
特点:
- 存储空间大小不固定,可以动态调整
- 空间很大
- 在JavaScript代码中,无法操作其内部存储,要使用地址读取 (运行效率低)
- 通过代码分配空间
复杂数据类型就不存在不可变性
,我们可以随意改变他们的值:
obj1.name="李四";
obj2.age=19;
Number类型
简称数字类型,可以表示整数和浮点数。在计算机中,数据都是以二进制
存储的。当进行计算的时候,数据都是以二进制
的形式进行计算,然后将结果转换为十进制
打印。 在这个过程中会发生一个很经典的问题:精度丢失
,这个问题发生在各种语言中。这是因为存储长度
的原因。
JS中对于二进制的存储方式
对于整数来说,除非超过最大范围,否则是不会存在精度
问题。主要问题在于小数
的存储。因为大多数小数
的二进制是无限循环
的。
ECMAScript
中的Number
类型遵循IEEE 754
标准。使用64
位固定长度来表示。
这其中包括:符合位
、 指数位
、尾数位
。
对于JavaScript
来说,它使用的是64
位双精度浮点数编码,所以它的符号位占1
位,指数位占11
位,尾数位占52
位。
(图片来自网络,侵权删)
- 符号位:就是表示这个数的正负关系,1表示负,0表示正
- 指数位:存储科学计数法的
指数
; - 尾数位:存储科学计数法的
有效
数字;
由于尾数位只能存储52
位,那么对于53
位的数字来说:第53
位及以后的数字是不能存储的,它遵循,如果是1
就向前一位进1
,如果是0
就舍弃的原则。这也就是为什么小数计算会产生误差,也就是经典的"0.1+0.2!=0.3"
。
null 和undefined
在ECMAScript
规定中,有两个特殊的数据类型,它们有且仅有一个值。
-
null
:仅有一个值null
,从逻辑上看,null表示一个空对象
指针,因为当我们使用typeof
操作符时,检测值为null
的变量会返回object
。我们可以利用这个值来销毁一些对象的行为。 -
undefined
:未定义的。当我们声明一个变量但是未对其赋值,这个变量的值就是undefined
。但是有特殊情况,当你直接调用一个未声明的变量时,这个变量时undefined
。
因为JavaScript
是一门动态语言,除了有表示空的null
之外,还可能根本就不存在,但是只有在代码运行时才能知道。JavaScript
中对于未初始化的变量会自动被赋予undefined
。
类型检测
typeof
通过typeof
操作符,我们很容易能区分出各种简单数据类型。
typeof 123 // number
typeof true // boolean
typeof '123' // string
typeof undefined // undefined
但对于复杂数据类型来说,因为存在特殊的对象,例如Date
、function
、Array
等等。
typeof [] // object
typeof {} // object
typeof new Array() // object
typeof function(){} //function
有一个特例,也就是函数(function)
。 其他都会被简单判定为object
。
instanceof
对于上面检测引用类型不准确的情况,instanceof
操作符能很好地帮助我们解决问题。
[] instanceof Array // true
new Date() instanceof Date // true
new RegExp() instanceof RegExp // true
instanceof
操作符的原理,简单来说就是,左侧
是否继承于右侧
。在JavaScript
中来说,左侧
是否在右侧
的原型链
上。
toString
对于引用类型来说,调用toString方法,可以实现引用类型到字符串的转换,并且返回"[object type]"
。这里的type
,就是这个对象的类型。
{}.toString() //[object Object]
但是经过我测试后发现,大部分特殊的对象不能实现正确输出。原来,比如Array
、Date
、RegExp
等都重写
了toString()方法,所以我们得不到正确答案。
那么我们怎么才能获得正确结果呢? 其实我们只要调用原始toString()方法就可以了,这时候我们就要借助原始类型上的方法:Object.prototype.toString().call(arg)
arg的值为特殊的对象。
最后
今天的分享就到这里了。虽然总结了不少细节知识,但肯定有我遗漏的知识,希望大家在阅读完毕之后提出宝贵意见!
本文地址:https://blog.csdn.net/qq_45786599/article/details/111873196
下一篇: 实现vuepc端自适应方案