Skip to content

JavaScript 数据类型

类型简介

JS 数据类型整体分为两大类:基本数据类型、引用数据类型

  • 基本数据类型:
    • number 数字型
    • string 字符串型
    • boolean 布尔型
    • symbol 标志型(不常用)
    • undefined 未定义型
    • null 空类型
  • 引用数据类型:
    • Object
    • Function
    • Array

image-20230531221423577

引用数据类型还有:DateRegExpMapSetErrorPromise

基本数据类型与引用数据类型在内存中的存储不同(操作系统层面):

  • 栈: 访问速度快,基本数据类型存放到
  • 堆: 存储容量大,引用数据类型存放到

image-20240507152733359

数字型

数字是最基本的数据类型,JavaScript 中的数字型不区分整型和浮点型。JS 是弱数据类型,变量类型只有在赋值之后,才能确认

  • 数学运算符也叫算术运算符,主要包括加、减、乘、除、取余(求模)
  • +:求和、 -:求差、*:求积、/:求商、 %:取模(取余数)

数字包装类型

number 有专门的构造函数Number,称为包装类型,除了字面量初始化数字型变量,也可以使用Number()构造函数

js
let num1 = 99
let num2 = new Number(88) // 这里是对象

一般使用前者较多,num1照样可以调用Number构造函数原型链上的方法,这个过程称为自动装箱,如:

js
const num = 99
const result = num.toFixed(2)
console.log(result) // "99.00"

在这个示例中,尽管num是一个原始的数字类型,你仍然可以调用toFixed()方法。这是因为:

  • JavaScript 引擎为数字 99 创建了一个Number包装对象
  • 在这个Number对象上调用了toFixed(2)方法
  • toFixed()方法返回了一个字符串 "99.00",该字符串被赋值给了变量 result
  • Number包装对象被销毁

包装类型是临时的,它们只在需要的时候被创建,一旦方法调用结束就会被销毁

NaN

NaN代表非数字(Not-a-Number)是一个特殊的值,用于表示一个操作数或操作数的结果不是合法数字。NaN 是粘性的,任何对 NaN 的操作都会返回 NaN

以下是一些可能导致NaN的情况:

  • 无效的算术操作: 当对一个或多个非数字值进行算术运算时,结果会是NaN
js
"hello" + 10 // NaN
Number({}) * 10 // NaN
  • 使用NaN作为操作数: 任何涉及NaN的操作都会产生NaN
js
10 * NaN // NaN
  • 错误的类型转换: 尝试将非数字字符串转换为数字,如果字符串格式不正确,会得到NaN
js
Number("123abc") // NaN
  • 科学计数法表示的过大数值: 当数值过大,超出了 JS 能表示的数字范围时,可能会返回NaN
js
Number("1e500") // NaN

由于NaN与任何值都不相等(包括自己)不能使用=====来检测NaN,正确的方式是使用全局的isNaN()函数

js
isNaN("hello") // true
isNaN(123) // false
isNaN(0 / 0) // true

字符串型

通过单引号 (' ')、双引号 (" ") 或反引号 ( `` ) 包裹的数据都叫字符串,JavaScript 中的单引号和双引号没有本质上的区别,推荐使用单引号

特点如下:

  • 单引号与双引号可以互相嵌套,但是不能自已嵌套自已,必要时可以使用转义符\来输出单引号或双引号
  • 通过 + 运算符,可以实现字符串的拼接
  • 字符串的值是不可变的,这意味着一旦字符串被创建就不能被改变,不过字符串是可以整体赋新值
  • 字符串取单字符可以使用charAt()[]

模板字符串

反引号 (``) 包裹,又称为模板字符串,用于拼接字符串和变量,内容拼接变量时用${}包住变量

  • 模板字符串可以直接包含换行符
js
const text = `
  Hello,
  How are you?
  Hope you are doing great.
`
  • 表达式可以嵌入到模板字符串中,表达式会在运行的过程中求值
js
const a = 5
const b = 10
const result = `The sum of ${a} and ${b} is ${a + b}.`
console.log(result) // The sum of 5 and 10 is 15.

标签函数

标签函数是一个特殊的函数调用形式,主要用于处理模板字符串。当在模板字符串之前放置一个函数名时,这个函数就会作为标签函数被调用

js
// 第一个参数是数组,包含了模板字符串中所有静态的部分(即不包含插值表达式的部分)
// 从第二个参数开始,是模板字符串中所有插值表达式求值后的值
function capitalize(strings, ...values) {
  return strings.map((str, i) => 
    str + (i < values.length ? ` ${values[i].charAt(0).toUpperCase() + values[i].slice(1)}` : '')
  ).join('')
}
const world = 'world'
const greeting = capitalize`Hello, ${world}`
console.log(greeting) // Hello, World
  • 模板字符串的.raw属性提供了模板字符串的原始形式,它将转义序列视为普通文本
js
const html = String.raw`<div>\n  <p>Hello, World!</p>\n</div>`
console.log(html) // <div>\n  <p>Hello, World!</p>\n</div>

字符串包装类型

string类型也有其对应的包装类型String,这也是为什么string类型能使用字符串方法的原因,同样涉及到自动装箱,与number类型类似

其属性及方法主要有:

  • length:获取字符串的长度
  • split('分隔符'):将字符串拆分成数组
  • substring(需要截取的第一个字符的索引[,结束的索引号]):字符串截取
  • startsWith(检测字符串[,检测位置索引号]):检测是否以某字符开头
  • endsWith(搜索的字符串[,检测终止位置索引号]):检测是否以某字符结尾
  • includes(搜索的字符串[,检测位置索引号]):判断一个字符串是否包含在另一个字符串中
  • trim():字符串的两端清除空格,返回一个新的字符串,而不修改原始字符串
  • toUpperCase()用于将字母转换成大写
  • toLowerCase():用于将就转换成小写
  • indexOf():检测是否包含某字符
  • replace(regexp):替换字符串,支持正则匹配
  • match(regexp):查找字符串,支持正则匹配

symbol

Symbol的值是唯一的,独一无二的,主要用于防止属性名冲突,如向第三方对象中添加属性

js
const symbol1 = Symbol()
const symbol2 = Symbol(42)
const symbol3 = Symbol('foo')
console.log(typeof symbol1) // "symbol"
console.log(symbol2 === 42) // false
console.log(symbol3.toString()) // "Symbol(foo)"
console.log(Symbol('foo') === Symbol('foo')) // false
  • 可以使用description获取传入的描述参数
js
const symbol = Symbol('foo')
console.log(symbol.description) // "foo"

for、keyFor

Symbol.for(key):接受一个字符串作为参数,并搜索一个具有该字符串描述的全局 Symbol 注册表

  • 如果找到了,就返回这个 Symbol
  • 如果没有找到,就创建一个新的 Symbol 并将其添加到全局注册表中,然后返回这个新创建的 Symbol

这意味着,当你使用相同的字符串作为参数调用 Symbol.for 时,你总是会得到相同的 Symbol 对象

js
let mySymbol = Symbol.for('mySymbol')
let anotherMySymbol = Symbol.for('mySymbol')
console.log(mySymbol === anotherMySymbol) // true

Symbol.keyFor(sym):接受一个 Symbol 对象作为参数,并返回该 Symbol 对象的全局描述字符串

  • 如果提供的不是 Symbol 对象,或者该 Symbol 对象没有在全局注册表中创建,则返回 undefined

这个方法通常用于反向查找 Symbol 对应的字符串键

js
let mySymbol = Symbol.for('mySymbol')
let anotherMySymbol = Symbol.for('mySymbol')

console.log(Symbol.keyFor(mySymbol)) // 'mySymbol'
console.log(Symbol.keyFor(anotherMySymbol)) // 'mySymbol'

遍历Symbol

Symbol 不能使用 for-infor-of 遍历,可以使用 Object.getOwnPropertySymbols(obj)Reflect.ownKeys(obj)获取所有Symbol属性。此外,这也意味着,如果对象属性不想被遍历,可以使用Symbol来保护

js
const myObject = {
  // 普通属性
  visibleProperty: 'This is visible',
  // 使用 Symbol 创建的属性
  [Symbol('hiddenProperty1')]: 'This is hidden1',
  [Symbol('hiddenProperty2')]: 'This is hidden2'
}


for (const key in myObject) {
  console.log(key + ' = ' + myObject[key])
}
// 只输出: visibleProperty = This is visible

for (const value of Object.values(myObject)) {
  console.log(value)
}
// 只输出: This is visible

const symbols = Object.getOwnPropertySymbols(myObject)
console.log(symbols) // [ Symbol(hiddenProperty1), Symbol(hiddenProperty2) ]

// 打印 Symbol 属性的值
symbols.forEach(sym => {
  console.log(sym.description + ' = ' + myObject[sym])
})
// 输出: hiddenProperty1 = This is hidden1
// 输出: hiddenProperty2 = This is hidden2

布尔类型

布尔类型只有两个固定的值:truefalse。与string、number类似,boolean也有包装类型Boolean

未定义与空类型

undefinednull都是表示没有值的特殊值,但它们的含义和用途不同:

undefined:

  • 当声明一个变量但未赋值则默认值为undefined
  • 函数没有返回值时,其返回值也是undefined
  • typeof undefined的结果是"undefined"

null:

  • null表示赋予变量空值,用来表示一个变量希望被赋予一个空或者不存在的值
  • null常用于初始化一个变量,表示它在逻辑上是一个空或者无效的引用
  • typeof null的结果是"object"(历史遗留问题,不建议依赖这个特性)

不同点:

  • undefined == null(true)、undefined === null(false)
  • undefined强转数字类型为NaNnull强制数字类型为0
  • undefined通常用于表示变量已声明但尚未初始化
  • null通常用于表示变量应该引用一个不存在的或者为空的对象

数据类型检测

通过typeof关键字检测数据类型,返回表示数据类型的字符串

typeof用法格式返回的字符串的值含义
typeof xundefined该值未定义
typeof(x)boolean该值为布尔类型
string该值为字符串类型
number该值为数值类型
object该值为对象(引用数据类型)或者null
function该值为函数类型

运算符与表达式

表达式

表达式指的是由运算符组成的式子,JS 引擎会将其计算出一个结果

js
//表达式一定会有运算结果
console.log(1 + 2)
let num = 1 + 2

运算符

算数运算与赋值运算符
算数运算符含义赋值运算符含义
+求和=直接赋值
-求差+=a = a + b
*求积*=a = a * b
/求商/=a = a / b
%取模(取余数)%=a = a % b
连接符(+)

用于字符串的拼接,+号只要遇到字符串,就是连接符(数字相加,字符相连)

js
document.write('Hello' + 'World') // HelloWorld
let first = 'Hello'
let second = 'World'
document.write(first + second) // HelloWorld
一元/三元运算符

一元运算符:++(自增)、-(自减)

  • 前置
js
let num = 1;
console.log(++num + 1 + ++num);//6
console.log(num);//3
  • 后置
js
let num = 1;
console.log(num++ + 1 + num++);//4
console.log(num);//3

三元运算符:条件 ? 满足条件执行的代码 : 不满足条件执行的代码

js
// 数字补零
num = num < 10 ? '0' + num : num
比较运算符
比较运算符含义
>左边是否大于右边
<左边是否小于右边
>=左边是否大于或等于右边
<=左边是否小于或等于右边
==左右两边值是否相等(强转)
===左右两边是否类型和值都相等(无强转)
!==左右两边是否不全等
逻辑运算符
符号名称特点
&&逻辑与符号两边都为true结果才为true
||逻辑或符号两边有一个为true true
!逻辑非取反

逻辑与、逻辑或可以作为短路运算符来使用:

  • 逻辑中断:存在于逻辑运算符&&||中,左边如果满足一定条件会中断代码执行,也称为逻辑短路
  • 当逻辑表达式结果不是布尔值时,会隐式转换为布尔值,但是最后运算结果,返回的不是布尔值,而是进行隐式转换之前的结果

逻辑运算符使用规则如下:

  • false && anything&&左边结果为false则中断, 否则返回右边代码的值
  • true || anything||左边结果为true则中断,否则返回右边代码的值
  • &&常常用来代替if(flag){}代码块
js
console.log(1 || 2) // 1,或运算,左边为true,逻辑中断,不用计算右边,直接输出或运算符左边的原结果,即1
console.log(1 || 0) // 1,或运算,左边为true,逻辑中断,不用计算右边,直接输出或运算符左边的原结果,即1
console.log(0 || 1) // 1,或运算,左边为false,右边计算为true,输出或运算符右边的原结果,即1
console.log(0 || 0) // 0,或运算,左边为false,右边计算为false,输出或运算符右边的原结果,即0
console.log(1 && 2) // 2,与运算,左边为true,右边计算为true,输出与运算符右边的原结果,即2
console.log(1 && 0) // 0,与运算,左边为true,右边计算为false,输出与运算符右边的原结果,即0
console.log(0 && 1) // 0,与运算,左边为false,逻辑中断,不用计算右边,直接输出与运算符左边的原结果,即0

//实际例子举例
let age = 10
console.log(true && age++) // 10,++在右边,不参与运算
console.log(true && ++age) // 12,++在左边,参与运算
console.log(age) // 12
运算符优先级
优先级运算符顺序
1小括号()
2一元运算符++--!
3算数运算符* / %+ -
4关系运算符> >=<<=
5相等运算符==!====!==
6逻辑运算符&&后`
7赋值运算符=
8逗号运算符,

类型转换

JavaScript 是弱数据类型,只有变量赋值时,才确定为何种数据类型

显示转换

转为数字型
方法含义
Number(数据)返回数字类型。字符串有非数字则为NaNnull转换为0undefinedNaN
parseInt(数据)只保留整数。如果为数字开头字符串则保留整数数字,非数字开头返回NaN
parseFloat(数据)可以保留小数。如果数字开头的字符串,可以保留小数

parseInt(string, radix)详解:

参数说明
string要解析的字符串
radix1) 可选。表示要解析的数字的基数。该值介于2 ~ 36之间

2) 如果省略该参数或其值为 0,则数字将以10为基础来解析。如果它以0x0X开头,将以16为基数;以1 ~ 9的数字开头,parseInt() 将把它解析为十进制的整数

3) 如果该参数< 2 or> 36,则 parseInt() 返回NaN

示例如下:

js
parseInt('689090',8)  //6  只解析小于8的
parseInt('8f89090',8)  //NaN  8不在8进制范围内
parseInt('8000',0)    //8000 以10为基数解析

//经典案例
["1", "2", "3"].map(parseInt) // [1, NaN, NaN]
//其实就是["1", "2", "3"].map((item, index)=>{return parseInt(item, index)})
转为字符型
方法含义
String(数据)返回字符串类型
toString(进制数)可以有进制转换,返回字符串类型
转为布尔型
  • Boolean(数据):返回true或者false
  • 空字符、0、-0、undefined、null、false、NaN转换为布尔值后为false,其余为true

隐式转换

某些运算符被执行时,系统内部自动将数据类型进行转换,这种转换称为隐式转换,如:

  • + 号作为运算符时,两边只要有一个是字符串,都会把另外一个转成字符串
  • 除了+以外的算术运算符,如 - * / 等都会把数据转成数字类型
  • +号作为正号解析可以转换成数字型
  • 逻辑非 ! 转换为布尔类型
最近更新