在JavaScript中,将数据类型分为两种:基础类型和复杂类型 两种类型的区别是:存储位置不同
1、基础类型
基础类型有以下6种:
- String
- Number
- Boolean
- Undefined
- BigInt (ES6新增)
- Null
- Symbol(ES6新增)
类型 | typeof 返回的值 | 对象包装器 |
---|---|---|
String | "string" | String |
Number | "number" | Number |
Boolean | "boolean" | Boolean |
Undefined | "undefined" | N/A |
Null | "object" | N/A |
BigInt | "bigint" | BigInt |
Symbol | "symbol" | Symbol |
String
JavaScript 字符串是不可变的。这意味着一旦字符串被创建,就不可能修改它。
let str = 'test'
str = str + 'spring' // 先删除再创建
语言规范要求字符串的最大长度为 253 - 1 个元素,这是精确整数的上限。但是,具有此长度的字符串需要 16384TB 的存储空间,这在任何合理的设备内存中都容纳不了,因此实现倾向于降低阈值,从而允许字符串的长度方便地存储在 32 位整数中。
- 在 V8(Chrome 和 Node 使用)中,最大长度为 229 - 24(~1GB)。在 32 位系统上,最大长度为 228 - 16(~512MB)。
- 在 Firefox 中,最大长度为 230 - 2(~2GB)。在 Firefox 65 之前,最大长度为 228 - 1(~512MB)。
- 在 Safari 中,最大长度为 231 - 1(~4GB)。
对于空字符串,length
为 0。
Number
常见的为十进制,还可以设置八进制(0开头)、十六进制(0x开头)
let intNum = 55 // 10进制的55
let num1 = 070 // 8进制的56
let hexNum1 = 0xA //16进制的10
浮点类型
let floatNum1 = 1.1;
let floatNum2 = 0.1;
let floatNum3 = .1; // 有效,但不推荐
let floatNum = 3.125e7; // 等于 31250000
NaN
= not a number
是一个特殊的数值
typeof NaN === 'number' // true
Number 类型仅有一个具有多个表现形式的值:0 同时表示为 -0 和 +0(其中 0 是 +0 的别名)。实际上,这两者之间几乎没有区别;例如,+0 === -0 是 true。然而,当你除以 0 的时候,你要注意到这一点:
console.log(42 / +0); // Infinity
console.log(42 / -0); // -Infinity
Number 类型是一种基于 IEEE 754 标准的双精度 64 位二进制格式的值。它能够存储 2-1074(Number.MIN_VALUE)和 21024(Number.MAX_VALUE)之间的正浮点数,以及 -2-1074 和 -21024 之间的负浮点数,但是它仅能安全地存储在 -(253 − 1)(Number.MIN_SAFE_INTEGER)到 253 − 1(Number.MAX_SAFE_INTEGER)范围内的整数。超出这个范围,JavaScript 将不能安全地表示整数;相反,它们将由双精度浮点近似表示。你可以使用 Number.isSafeInteger() 检查一个数是否在安全的整数范围内。 ±(2-1074 到 21024) 范围之外的值会自动转换:
- 大于 Number.MAX_VALUE 的正值被转换为 +Infinity。
- 小于 Number.MIN_VALUE 的正值被转换为 +0。
- 小于 -Number.MAX_VALUE 的负值被转换为 -Infinity。
- 大于 -Number.MIN_VALUE 的负值被转换为 -0。
+Infinity 和 -Infinity 行为类似于数学上的无穷大,但是有一些细微的区别;更多细节,参见 Number.POSITIVE_INFINITY 和 Number.NEGATIVE_INFINITY。
Boolean
[Boolean](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Boolean)
类型表示一个逻辑实体并且包括两个值:true
和 false
。
Undefined
Undefined
类型只有一个值:[undefined](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined)
。
Undefined
表示已经定义但未赋值。
Null
Null 类型只有一个值:[null](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/null)
。
Null
代表一个空指针在栈内存中找不到其值地址指向。
值 null
是一个字面量,不像[undefined](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefined)
,它不是全局对象的一个属性。null
是表示缺少的标识,指示变量未指向任何对象。把 null
作为尚未创建的对象,也许更好理解。在 API 中,null
常在返回类型应是一个对象,但没有关联的值的地方使用。
BigInt
BigInt
是一种数字类型的数据,它可以表示任意精度格式的整数,使用 BigInt 可以安全地存储和操作大整数,即使这个数已经超出了 Number
能够表示的安全整数范围。
Symbol
[Symbol](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Symbol)
是唯一并且不可变的原始值并且可以用来作为对象属性的键(如下)。在某些程序语言当中,Symbol
也被称作“原子类型”(atom)。symbol
的目的是去创建一个唯一属性键,保证不会与其它代码中的键产生冲突。
2、引用类型
引用数据类型:
- Object
- Array
- Function
Object
创建object常用方式为对象字面量表示法,属性名可以是字符串或数值 类数组创建方式
const arrayLike = {
lenth: 3,
0: 'a',
1: 'b',
2: 'c'
}
console.log(Array.from(arrayLike)) // ['a', 'b', 'c']
console.log(arrayLike instanceof Array); // false
console.log(arrayLike.__proto__.constructor === Array); // false
console.log(arrayLike.toString()); // [object Object]
console.log(arrayLike.valueOf()); // {length: 3, 0: 'a', 1: 'b', 2: 'c'}
let array = [];
console.log(array instanceof Array); // true
console.log(array.__proto__.constructor === Array); // true
console.log(array.toString()); // ''
console.log(array.valueOf()); // []
Array
JavaScript数组是一组有序的数据,但跟其他语言不同的是,数组中每个槽位可以存储任意类型的数据。并且,数组也是动态大小的,会随着数据添加而自动增长
Function
函数实际上是对象,每个函数都是 Function
类型的实例,而 Function
也有属性和方法,跟其他引用类型一样
函数存在三种常见的表达方式:
- 函数声明
// 函数声明
function sum (num1, num2) {
return num1 + num2;
}
- 函数表达式
let sum = function(num1, num2) {
return num1 + num2;
};
- 箭头函数
let sum = (num1, num2) => {
return num1 + num2;
};
3、存储区别
基本类型
let a = 10;
let b = a; // 赋值操作
b = 20;
console.log(a); // 10值
a
的值为一个基本类型,是存储在栈中,将a
的值赋给b
,虽然两个变量的值相等,但是两个变量保存了两个不同的内存地址
下图演示了基本类型赋值的过程:
引用类型
var obj1 = {}
var obj2 = obj1;
obj2.name = "Xxx";
console.log(obj1.name); // xxx
引用类型数据存放在堆中,每个堆内存对象都有对应的引用地址指向它,引用地址存放在栈中。
obj1
是一个引用类型,在赋值操作过程汇总,实际是将堆内存对象在栈内存的引用地址复制了一份给了obj2
,实际上他们共同指向了同一个堆内存对象,所以更改obj2
会对obj1
产生影响
下图演示这个引用类型赋值过程:
总结
- 栈:原始数据类型(
Undefined
、Null
、Boolean
、Number
、String
、BigInt
、Symbol
) - 堆:引用数据类型(
Object
、Array
、Function
)
两种类型的区别在于存储位置的不同:
- 原始数据类型直接存储在栈(
stack
)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储; - 引用数据类型存储在堆(
heap
)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
堆和栈的概念存在于数据结构和操作系统内存中,在数据结构中:
- 在数据结构中,栈中数据的存取方式为先进后出。
- 堆是一个优先队列,是按优先级来进行排序的,优先级可以按照大小来规定。
在操作系统中,内存被分为栈区和堆区:
- 栈区内存由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
- 堆区内存一般由开发着分配释放,若开发者不释放,程序结束时可能由垃圾回收机制回收。