说明

​每天10分钟,重构你的前端知识体系​​专栏笔记。

一、介绍

在 JavaScript 标准中,把语句分成了两种:普通语句和声明型语句。

1.1、普通语句

重学前端 31 # JavaScript的语句_i++

1.2、声明型语句

重学前端 31 # JavaScript的语句_javascript_02

二、语句块

语句块就是一对大括号。

{
var x, y;
x = 10;
y = 20;
}

语句块的意义和好处在于:让我们可以把多行语句视为同一行语句。

// 语句块会产生作用域
{
let x = 1;
}
console.log(x); // Uncaught ReferenceError: x is not defined

三、空语句

空语句就是一个独立的分号,实际上没什么大用。

;

四、if 语句

if(a < b)
console.log(a);

if 和 else 连写成多分支条件

if(a < 10) {
//...
} else if(a < 20) {
//...
} else if(a < 30) {
//...
} else {
//...
}

五、switch 语句

switch(num) {
case 1:
console.log(1);
case 2:
console.log(2);
case 3:
console.log(3);
}
// num等于1,输出:1 2 3
// num等于2,输出:2 3
// num等于3,输出:3

switch(num) {
case 1:
console.log(1);
break;
case 2:
console.log(2);
break;
case 3:
console.log(3);
break;
}
// num等于1,输出:1
// num等于2,输出:2
// num等于3,输出:3

winter 的看法是:“ switch 已经完全没有必要使用了,应该用 if else 结构代替。”。

六、循环语句

6.1、while 循环和 do while 循环

let a = 5;
while(a--) {
console.log("*");
}
// 输出:* * * * *
let a = 6;
do {
console.log(a);
} while(a < 6)
// 6

6.2、普通 for 循环

for(i = 0; i < 6; i++)
console.log(i);
// 0 1 2 3 4 5

for(var i = 0; i < 6; i++)
console.log(i);
// 0 1 2 3 4 5

for(let i = 0; i < 6; i++)
console.log(i);
// 0 1 2 3 4 5

for(const i = 0; i < 6; i++)
console.log(i);
// 0 Uncaught TypeError: Assignment to constant variable.

var j = 0;
for(const i = 0; j < 6; j++)
console.log(i);
// 0 0 0 0 0 0

6.3、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
// enumerable为true,输出:a b c

6.4、for of 循环和 for await of 循环

for of 循环是非常棒的语法特性​​。背后的机制是 ​​iterator​​ 机制。

1、用于数组

for(let e of [1, 2, 3, 4, 5])
console.log(e);
// 1 2 3 4 5

2、如何为一个对象添加 ​​iterator​​。

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);
// 0 1 2 3 4 5 6 7 8 9

3、使用 ​​generator function​​。

function* foo(){
yield 0;
yield 1;
yield 2;
yield 3;
}
for(let e of foo())
console.log(e);
// 0 1 2 3

4、JavaScript 还为异步生成器函数配备了异步的 for of

function sleep(duration) {
return new Promise(function(resolve, reject) {
setTimeout(resolve,duration);
})
}
async function* foo(){
i = 0;
while(true) {
await sleep(1000);
yield i++;
}
}
for await(let e of foo())
console.log(e);
// 从0开始,每隔1s加1,输出:0 1 2 3 4 5....

七、return

return 语句用于函数中,它终止函数的执行,并且指定函数的返回值。

function squre(x){
return x * x;
}

八、break 语句和 continue 语句

break 语句用于跳出循环语句或者 switch 语句,continue 语句用于结束本次循环并继续循环。

for(let i = 0; i < 2; i++){
console.log(i)
if( i == 0){
break;
}
}
// 0

for(let i = 0; i < 2; i++){
console.log(i)
if( i == 0){
continue;
}
}
// 0 1

九、with 语句

with 语句把对象的属性在它内部的作用域内变成变量。

let o = {a:1, b:2}
with(o){
console.log(a, b);
}
// 1 2

十、try 语句和 throw 语句

try 语句和 throw 语句用于处理异常。try 语句用于捕获异常,用 throw 抛出的异常。

  • ​try​​ 部分用于标识捕获异常的代码段
  • ​catch​​​ 部分则用于捕获异常后做一些处理(​​catch结构​​会创建一个局部的作用域,不能再声明变量 e ,否则会出错。)
  • ​finally​​ 语句一般用于释放资源,它一定会被执行
try {
throw new Error("error");
} catch(e) {
console.log(e);
} finally {
console.log("finally");
}
// Error: error at <anonymous>:2:1
// finally

十一、debugger 语句

debugger 语句的作用是​:通知调试器在此断点。在没有调试器挂载时,它不产生任何效果。

十二、var

1、var 声明语句是古典的 JavaScript 中声明变量的方式。而现在,基本使用 let 和 const 。

2、如果仍然想要使用 var,winter建议:把它当做一种​​保障变量是局部​​的逻辑,遵循以下三条规则:

  • 声明同时必定初始化
  • 尽可能在离使用的位置近处声明
  • 不要在意重复声明
// 下面这里x声明了两次
function add(x,y) {
console.log(x + y);
}
function multiply(x,y) {
console.log(x * y);
}

var x = 1, y = 2;
add(x, y);

for(var x = 0; x < 2; x++)
multiply(x,y);
// 3
// 0
// 2

// 使用let改造,用代码块限制了第一个 x 的作用域,这样就更难发生变量命名冲突引起的错误。
{
let x = 1, y = 2;
add(x, y);
}

for(let x = 0; x < 2; x++)
multiply(x);

十三、let 和 const

const a = 2;
if(true){
const a = 1;
console.log(a);
}
console.log(a);
// 1 2

1、const 和 let 语句在重复声明时会抛错,这能够有效地避免变量名无意中冲突。

let a = 2
const a = 1;
// Uncaught SyntaxError: Identifier 'a' has already been declared

2、let 和 const 声明还是会被预处理。如果当前作用域内有声明,就无法访问到外部的变量。

const a = 2;
if(true){
console.log(a); // 抛错
const a = 1;
}
// Uncaught ReferenceError: Cannot access 'a' before initialization

if(true){
console.log(a);
var a = 1;
}
// undefined

// 上面的对比就说明 const 声明仍然是有预处理机制的。

十四、class 声明

​class​​​ 最基本的用法只需要 ​​class​​ 关键字、名称和一对大括号。

1、​​class​​​ 的声明特征跟 ​​const​​​ 和 ​​let​​ 类似,都是作用于块级作用域,预处理阶段则会屏蔽外部变量。

const a = 2;
if(true){
console.log(a); // 抛错
class a {

}
}
// Uncaught ReferenceError: Cannot access 'a' before initialization

2、​​class​​​ 内部,可以使用 ​​constructor​​ 关键字来定义构造函数。

// 这个例子来自 MDN,它展示了构造函数、getter 和方法的定义。
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea();
}
// Method
calcArea() {
return this.height * this.width;
}
}

十五、函数声明

函数声明使用 function 关键字。

1、带 * 的函数是 ​​generator​​​。生成器函数可以理解为返回一个序列的函数,它的底层是 ​​iterator​​ 机制。

2、​​async​​​ 函数是可以暂停执行,等待异步操作的函数,它的底层是 ​​Promise​​ 机制。

function foo(){

}

function* foo(){
yield 1;
yield 2;
yield 3;
}

async function foo(){
await sleep(3000);
}

async function* foo(){
await sleep(3000);
yield 1;
}

3、函数的参数,可以只写形参名,还可以写默认参数和指定多个参数

function foo(a = 1, ...other) {
console.log(a, other)
}

foo();
// 1 []

foo(3,4);
// 3 [4]