表达式(Expression)
定义: 表达式是会计算并返回一个值的代码片段
特点:
- 表达式总是有返回值
- 表达式可以出现在任何需要值的地方,可以出现在赋值语句、函数参数、控制流语句的条件部分等需要值的地方,例如
let x = (1 + 2)
示例:
42; // 数字表达式,返回值是 42
"Hello"; // 字符串表达式,返回值是 "Hello"
1 + 2; // 算术表达式,返回值是 3
console.log("Big number") // 函数是表达式,此函数返回值: undefined
语句(Statement)
定义: 语句是用于执行某种操作的代码块,包括控制流、声明、循环等。例如:if (...) {}、for (...) {}、let x = 5;、return 42;
特点:
- 语句通常不返回值,或者返回值不被直接使用。语句一般由多个部分构成,执行一个操作。
- 语句的内容可以包含表达式,表达式本身可以作为语句的一部分。
示例:
let a = 1; // 声明语句
if (true) {} // 条件语句
for (let i = 0; i < 10; i++) {} // 循环语句
表达式和语句的关系
关系: 表达式和语句并不是一个维度,更像是**“内容 vs. 结构”**的关系,而不是两种并列的类型。
- 表达式 = 计算并返回一个值
- 语句 = 执行某个操作,是代码的一个组成部分,可能包含多个表达式,但通常没有返回值
语句可以包含表达式,但表达式本身不是语句的一种,而是语句的组成部分
示例:
let x = 1 + 2;
1 + 2是表达式(计算并返回 3)x = 1 + 2是表达式,赋值表达式let x = 1 + 2是语句(执行赋值操作)
if (x > 10) { console.log("Big number"); }
x > 10是表达式(计算出 true 或 false)console.log("Big number")是表达式,只是返回 undefinedif (...) {}是语句(执行分支逻辑)
表达式语句(Expression Statement)
定义: 当一个表达式独立成行时,它会被视为表达式语句。它会执行表达式并丢弃其返回值
示例:
"Hello"; // 表达式语句
1 + 2; // 表达式语句
console.log("Hi"); // 也是表达式语句(函数调用也是表达式)
本质上,表达式语句仍然是语句,但它的内容是一个表达式。
特殊的表达式
某些语句单独成行使用时,不是表达式语句,但在某些情况下使用会被视为表达式
函数声明和类声明
function fun() {}
class A {}
1. 函数声明和类声明单独成行使用时
它们只是声明语句,不是表达式语句,它的作用是创建函数或类的绑定,不会直接返回值;
2. 用括号括起来,并在单独成行的情况下是表达式语句
(function() {}); // 函数表达式语句,也可以是具名函数
(class {}); // 类表达式语句,也可以是具名类
// 匿名函数和匿名类 不被括号包裹,单独成行时,会报语法错误
3. 做为函数参数使用时,是表达式
console.log(function () {}); // 函数表达式
console.log(class {}); // 类表达式
4. 赋值语句中使用时,是表达式
let foo = function() {} // 函数也可以是具名函数
let MyClass = class {}; // 类也可以是具名类
function() {} 此时是一个表达式,因为他返回了一个函数,并赋值给了foo
class {} 此时是一个表达式,因为他返回了一个类,并赋值给了MyClass
语法上,它们是声明赋值语句的一部分,包含了 函数表达式 或 类表达式。因为它们的主要功能是定义函数或类,大家为了简化和突出它们的作用,整个语句通常称其为 函数表达式 或 类表达式
5. 默认导出语句中使用时,是表达式
export default function() {}
export default class {}
function() {} 此时是一个表达式,因为他返回了一个函数,并被默认导出
class {} 此时是一个表达式,因为他返回了一个类,并被默认导出
6. 注意
- 函数声明有提升效果,可以在定义前调用。
- 函数表达式没有提升效果,必须在定义后调用。
- 函数表达式如果没有赋值给变量,外部无法访问(即使是具名函数)。
- 立即执行函数表达式(IIFE):
- 匿名 IIFE 无法通过函数名递归调用自身。
- 具名 IIFE 可以通过函数名递归调用自身。
- 非严格模式下,匿名函数可以通过
arguments.callee访问自身。
- 类表达式如果没有赋值给变量,外部无法访问(即使是具名类)。
import 语句
import a from './module.js';
let module = import('./module.js');
import 语句本质上是 模块导入的声明,不能作为表达式使用,也不会返回值。
import() 执行调用时,会返回一个 Promise 对象,代表异步加载模块的结果。是表达式
总结
- 表达式是计算值并返回结果的代码片段。表达式可以作为语句的一部分,但在独立使用时,称为表达式语句,执行计算并丢弃返回值。
- 语句是执行某个操作的代码块,它不直接返回一个值,语句可能包含多个表达式。
- 函数声明和类声明单独使用时是声明语句,但它们在一个语句中作为值使用时是表达式,返回一个函数或类。
- 函数作为表达式运行时,将没有函数提升效果,且如果没有赋值给其它变量,外部将不能访问此函数。
import语句是声明,不是表达式,而import()作为表达式使用时返回一个Promise。
JavaScript 中的表达式常见分类
| 分类 | 说明 | 示例 |
|---|---|---|
| 1. 原始表达式(Primary Expressions) | 直接返回值的最基础表达式 | 42, "Hello", true, null, undefined, this, a |
| 2. 算术表达式 | 计算数值的表达式 | 1 + 2, -a, ++a |
| 3. 逻辑表达式 | 计算布尔值的表达式 | true && false, !true, `a |
| 4. 比较表达式 | 用于比较两个值 | a === b, a > b |
| 5. 赋值表达式 | 给变量赋值的表达式 | a = 5, a += 2 |
| 6. 条件(三元)表达式 | if语句的简写形式 | a > b ? a : b |
| 7. 函数表达式 | 必须用 ()包裹或赋值 | (function() {}), const foo = function() {}; |
| 8. 类表达式 | 必须用 ()包裹或赋值 | (class {}), const MyClass = class {}; |
| 9. 对象和数组表达式 | 直接创建对象或数组 | { name: "Alice" }, [1, 2, 3] |
| 10. 模板字符串表达式 | 通过模板字符串拼接 | `Hello, ${name}!` |
| 11. 可调用表达式(调用和 new) | 调用函数或构造实例 | foo();, obj.method();, new Date(); |
| 12. 成员访问表达式 | 访问对象或数组的成员 | obj.name, arr[0] |
| 13. 分组表达式 | 控制运算优先级(不影响类型) | (1 + 2) * 3 |
| 14. 动态导入表达式 | 动态加载模块的表达式 | import('./module.js') |