在JavaScript标准中,把语句分成了两种:声明和语句。
普通语句
-
语句块
-
空语句
-
表达式语句
-
if语句
-
switch语句
-
循环语句
- for循环
- for in循环
- for of循环
- for await of循环
- while循环
- do while循环
-
return语句
-
break语句
-
continue语句
-
with语句
-
throw语句
-
try语句
-
debugger语句
声明型语句
- var语句
- let语句
- const语句
- class声明
- 函数声明
- 普通函数声明
- async函数声明
- generator函数声明
- async generato函数声明
语句块
语句块就是一对大括号。让我们把多行语句是为同一行语句,这样,if、for等语句定义起来就比较简单。 需要注意语句块会形成作用域
{
let x = 1;
}
console.log(x); //error
let声明仅仅对语句块作用域生效,在作用域外访问x就会报错。
空语句
空语句就是一个分号,仅仅用于语言设计完备性,允许插入多个分号而不抛出错误。
;
if语句
if 语句比较熟悉,if () {} else if () {} else {}就是可以分支。
switch语句
switch是继承自Java,Java继承自C和C++, switch是跳转的变形,如果要分支,就必须加上break。在C时代,switch是性能是略优于if else的,对JS并无本质区别。
循环语句
while循环和 do while 循环
let a = 100;
while (a--) {
console.log("*");
}
let a= 101;
do {
console.log(a);
} while (a < 100)
do while循环无论如何至少执行一次。
普通 for 循环
for in 循环
for in 循环枚举对象的属性,体现了enumerable特征。
let o = {a: 10, b: 20};
Object.defineProperty(o, "c", {enumerable: false, value: 30})
for(let p in o)
console.log(p); //a b
for of循环和 for await of 循环
for (let e of [1, 2, 3, 4, 5]){
console.log(e)
}
// 1 2 3 4 5
背后的机制是iterator机制。可以给一个对象添加iterator,使它可以用于for of语句,如下:
let o = {
[Symbol.iterator]: () => ({
_value: 0,
next() {
if (this._value = 10) {
return {
done: true
}
}
else return {
value: this._value++,
done: false
};
}
})
}
for(let e of o)
console.log(e);
这段代码展示了如何为一个对象添加iterator。但是实际操作的时候,不需要定义iterator,可以使用generator function。
function* foo() {
yield 0;
yield 1;
yield 2;
yield 3;
}
for (let e of foo()) {
console.log(e);
}
// 0 1 2 3
上面代码展示了generator function和foo的配合。
return
return用户函数中,终止函数的执行,并且制定函数的返回值。
function squre(x) {
return x * x;
}
break语句和continue语句
这两个都是控制型语句,用法比较相似。需要注意的是,他们都可以有带标签的用法。
outer: for(let i = 0; i < 100; i++)
inner: for(let j = 0; j < 100; j++)
if (i == 50 && j == 50)
break outer;
outer: for(let i = 0; i < 100; i++)
inner: for(let j = 0; j < 100; j++)
if ( i >= 50 && j == 50)
continue outer;
带标签的break和continue可以控制自己被外层的哪个语句消费,可以跳出复杂的语句结构。
with语句
let o = {a: 1, b: 2};
with(o) {
console.log(a, b);
}
with语句把对象的属性在内部作用域内变成了变量。
try语句和throw语句
try语句和throw语句用于处理异常,他们是配合使用的。在大型应用中,异常机制非常重要。
try {
throw new Error("error");
} catch(e) {
console.log(e);
} finally {
console.log("finally");
}
try语句捕获异常,throw抛出异常,可以在try语句的结构中被处理掉: try部分用于标识捕获异常后的代码段,catch部分用于捕获异常后做一些处理,finally用于执行后做一些必须执行的清理工作。即使try中出现了return, finally中的语句也一定要被执行。
debugger语句
通知调试器在此断点。
----------------------------------------------------------------------
普通语句和声明型语句的交界线
----------------------------------------------------------------------
var
var声明是古典的JS声明变量的方式,如今let和const都是更好的选择。 如果仍然使用var,把它当做一种“保障变量是局部”的逻辑,遵循以下三条规则:
- 声明同时必定初始化
- 尽可能在离使用的位置近处声明
- 不要在意重复声明
let 和 const
let和const 看起来都是执行到了才生效,但是应该预处理过。
const a = 20;
if (true) {
console.log(a);
const a = 2;
}
// error. Cannot access 'a' before initialization
执行console.log的时候,如果const 声明没有被预处理,就不该报错。在执行的时候已经知道后面代码有变量a,于是不允许访问外层作用域的a。(暂时性死区,TDZ)
class声明
class内部可以使用constructor关键字定义构造函数, getter, setter方法。默认内部的函数是strict模式的。
函数声明
函数声明有几种类型
function foo() {}
funtion* foo() {
yield 1;
yield 2;
}
async function foo() {
await sleep(3000)
}
async function* foo() {
await sleep(3000);
yield;
}
带*的函数是generator,生成器函数可以理解为返回一个序列的函数,底层是iterator机制。 async函数是可以暂停执行,等待异步操作的函数,底层是Promise机制。异步生成器是两者的结合。
重学前端是程劭非(winter)【前手机淘宝前端负责人】在极客时间开的一个专栏, 每天10分钟,重构你的前端知识体系。在学习了JavaScript语句这一章节以后,抄录归纳了这些内容。