本页面探讨了构成JavaScript语言基础的基本构建块。我们将审视原始类型、值类型与引用类型、类型转换机制,以及表达式与语句的区别。理解这些核心概念对于精通JavaScript编程和避免常见陷阱至关重要。
有关函数作用域和词法作用域的相关信息,请参阅函数作用域、块作用域和词法作用域。
根据ECMAScript规范,JavaScript有六种原始数据类型:string、number、bigint、boolean、undefined和symbol。还有一个特殊的原始值称为null。原始值是不可变的,并且直接按值存储。
| 类型 | 描述 | 示例 | typeof 结果 |
|---|---|---|---|
| 字符串 | 文本数据 | 'Hello', "World" | 'string' |
| 数字 | 数值(IEEE 754) | 42, 3.14, NaN, Infinity | 'number' |
| 布尔值 | 逻辑值 | true, false | 'boolean' |
| 未定义 | 声明但未赋值的变量 | 未定义 | 'undefined' |
| null | 有意缺失的值 | null | 'object'(语言怪癖) |
| symbol | 唯一且不可变的标识符 | Symbol('id') | 'symbol' |
| bigint | 大整数 | 9007199254740991n | 'bigint' |
虽然原始类型本身没有方法,但当您尝试在原始类型上调用方法时,JavaScript会自动用对象对应物包装它们,这个过程称为“自动装箱”。
在JavaScript中,值的存储和访问方式取决于它是原始类型(值类型)还是对象(引用类型)。这种基本区别对变量赋值和比较有显著影响。
| 方面 | 值类型(原始类型) | 引用类型(对象) |
|---|---|---|
| 存储 | 直接存储在变量位置 | 存储在堆中,变量包含一个引用 |
| 作业 | 创建值的副本 | 创建引用的副本 |
| 比较 | 比较实际值 | 比较引用(内存地址) |
| 变异 | 不可修改(不可变) | 可修改(可变) |
处理原始类型时,变量是独立的
处理对象时,变量指向相同的数据
JavaScript是动态类型语言,在操作涉及不同类型时会执行自动类型转换(强制转换)。理解JavaScript如何在类型之间转换对于编写可预测的代码至关重要。
JavaScript有两种相等运算符
| 运算符 | 姓名 | 行为 |
|---|---|---|
== | 宽松相等 | 在比较前执行类型强制转换 |
=== | 严格相等 | 比较值和类型,不进行强制转换 |
| 表达式 | 结果 | 解释 |
|---|---|---|
5 == "5" | true | 字符串“5”被强制转换为数字5 |
5 === "5" | false | 不同类型(数字 vs 字符串) |
null == undefined | true | 在宽松相等中,两者都表示“无值” |
null === undefined | false | 不同类型 |
0 == false | true | 两者都强制转换为数字0 |
0 === false | false | 不同类型(数字 vs 布尔值) |
`typeof`运算符返回一个字符串,指示操作数的类型
当值转换为布尔值时,它们会变成“真值”或“假值”
| 假值 | 真值 |
|---|---|
false | 不在假值列表中的其他所有值 |
0, -0, 0n | 非零数字 |
"" (空字符串) | 非空字符串 |
null | 对象(即使是空对象) |
未定义 | 数组(即使是空数组) |
NaN | 函数 |
JavaScript区分表达式(产生值的代码)和语句(执行操作的代码)。这种区别对于理解代码如何被评估和执行很重要。
| 功能 | 表达式 | 语句 |
|---|---|---|
| 目的 | 产生值 | 执行操作 |
| 用途 | 可在需要值的地方使用 | 程序的顶层组件 |
| 作业 | 可赋值给变量 | 不可赋值给变量 |
| 返回值 | 有返回值 | 无返回值 |
函数声明和函数表达式之间存在关键区别
函数声明会被提升(在编译过程中移到其作用域的顶部),这意味着它们可以在代码中出现之前被调用。然而,函数表达式的提升方式不同,只能在定义后调用。
某些表达式可以通过添加分号作为语句使用,称为表达式语句
理解表达式和语句之间的区别对于JavaScript开发至关重要,尤其是在处理箭头函数、三元运算符和立即调用的函数表达式(IIFE)等功能时。
JavaScript的类型系统可以通过多种方式进行分类,这有助于理解其与其他编程语言的行为差异。
JavaScript提供了隐式和显式类型转换的机制
| 转换类型 | 描述 | 示例 |
|---|---|---|
| 隐式(强制转换) | JavaScript自动转换 | "5" + 2(变成"52") |
"5" - 2(变成3) | ||
if ("text")(转换为true) | ||
| 显式(类型转换) | 开发者手动转换 | Number("5")(变成5) |
String(123)(变成"123") | ||
Boolean(0)(变成false) |
虽然JavaScript本身不支持名义类型(其类型兼容性基于显式声明),但TypeScript等库添加了此功能。然而,JavaScript确实表现出结构化类型的特征
这展示了JavaScript的结构化类型特性,其兼容性由对象的属性和方法决定,而不是其声明的类型。
理解JavaScript的语言基础可以帮助您避免常见的陷阱,从而编写更可预测、更易于维护的代码。
| 场景 | 推荐方法 | 避免 |
|---|---|---|
| 相等比较 | 使用===以获得可预测的结果 | 除非特别需要类型强制转换,否则使用== |
| 类型检查 | typeof x === 'string' | 依赖隐式类型转换 |
null/undefined检查 | x === null或x === undefined | 除非您想同时匹配两者,否则对这些检查使用== |
| 数组检查 | Array.isArray(x) | typeof x === 'array'(返回‘object’) |
| NaN检查 | Number.isNaN(x) | x === NaN(总是false) |
当您需要独立的副本时,请使用对象克隆
注意函数中的引用行为
显式进行类型转换以提高清晰度
使用适当的类型转换函数
谨慎管理数值运算
理解并正确应用这些JavaScript基础知识将帮助您编写更可靠、更易于维护的代码。