1.表达式与语句
JavaScript 程序的执行单位为行(line),也就是一行一行地执行。一般情况下,每一行就是一个语句。
比如下面就是一行赋值语句。
var a = 1 + 3;
其中1+3
是表达式(expression)
,表达式是一个计算式,为了得到一个返回值。
1+3 //表达式的值为4
add(1,2) //表达式的值为函数的返回值
console.log() //表达式的值为console.log()
console.log(3) //表达式的值为 undefined
表达式和语句的区别
①
表达式
是一个计算式,一定会有一个返回值。
语句
是一步要执行的操作,一般改变环境(声明、变量)。一般情况不会返回值。
②
表达式
不需要分号结尾。一旦在表达式后面添加分号,则 JavaScript 引擎就将表达式视为语句,这样会产生一些没有任何意义的语句。
1 + 3 ; //只是单纯地产生一个值,没有实际的意义。
语句
以分号结尾,一个分号就表示一个语句结束。多个语句可以写在一行内。
2.大小写、空格和换行
首先,JavaScript是大小写敏感的。
var a
和var A
是不一样的;
object
和Object
是不一样的;
function
和Function
是不一样的。大多数空格没有实际意义
var a=1
和var a = 1
是一样的。加回车大部分时候也没有影响,但
return
后面不能加回车。
return
3 //这里return 3 不写到一行的话,会返回undefined
3.标识符
标识符(identifier)指的是用来识别各种值的合法名称。最常见的标识符就是变量名,以及后面要提到的函数名。
标识符有一套命名规则,不符合规则的就是非法标识符。JavaScript 引擎遇到非法标识符,就会报错如下。
Uncaught SyntaxError: Invalid or unexpected token
未捕获的语法错误:无效或意外的字符串
标识符命名规则:
- 第一个字符,可以是任意 Unicode 字母(包括英文字母和其他语言的字母),以及美元符号(
$
)和下划线(_
)。 - 第二个字符及后面的字符,除了 Unicode 字母、美元符号和下划线,还可以用数字
0-9
。
下面这些都是合法的标识符。
a1
$8
_last
π
下面这些则是不合法的标识符。
1a // 第一个字符不能是数字
23 // 同上
*** // 标识符不能包含星号
a+b // 标识符不能包含加号
-d // 标识符不能包含减号或连词线
中文也是合法的标识符,可以用作变量名。
var 临时变量 = 1;
4.注释
源码中被 JavaScript 引擎忽略的部分就叫做注释,它的作用是对代码进行解释。
JavaScript 提供两种注释的写法:
- 一种是单行注释,用
//
起头; - 另一种是多行注释,放在
/*
和*/
之间。
// 这是单行注释
/*
这是
多行
注释
*/
<!-- 这也是单行注释。由于历史上 JavaScript 可以兼容 HTML 代码的注释-->
优秀的注释应该写最关键的内容,比如:
- 踩坑注解;
- 此处遇到bug后,加了XXX代码;
- 解释某处奇怪的代码是因为某些特殊需求。
5.区块block
JavaScript 使用大括号,将多个相关的语句组合在一起,称为“区块”(block)。
在 JavaScript 语言中,单独使用区块并不常见,区块往往用来构成其他更复杂的语法结构,常与if
、 for
、while
、function
一起使用。
6.条件语句
6.1 if else
语法:if(表达式){语句1}else{语句2}
。
执行顺序:表达式为真执行语句1,表达式为假则跳过语句1直接执行语句2。
{}
在只有一行语句的时候可以省略,但不建议省略。原因是为了后面方便插入新的语句。
坑
- 在
if
后面的表达式之中,a=1
是赋值表达式,不具有比较作用。这里要写成严格相等运算符(===
)。如a===1
。
此处待补充:为什么优先采用“严格相等运算符”(===
),而不是“相等运算符”(==
)。 - 如果省略
{}
,见下面代码:
a = 1
if(a===2)
console.log('a')
console.log('a等于2')
正确输出是:a等于2
。因为它的完整格式如下:
a = 1
if(a===2){
console.log('a')
}else{
console.log('a等于2')
}
为避免歧义,最推荐下面结构写代码
if (表达式){
语句1
}else if (表达式){
语句2
}else {
语句3
}
6.2 switch case
多个if...else
连在一起使用的时候,可以转为使用更方便的 switch
结构。
语法:
switch (fruit) {
case "banana":
// ...
break;
case "apple":
// ...
break;
default:
// ...
}
上面代码根据变量fruit
的值,选择执行相应的case
。如果所有case
都不符合,则执行最后的default
部分。需要注意的是,每个case
代码块内部的break
语句不能少,否则会接下去执行下一个case代码块,而不是跳出switch结构。
6.3 三元运算符
问号冒号表达式
语法:表达式1?表达式2:表达式3
7. 短路逻辑
7.1 && 与
A&&B&&C&&D 取按顺序出现的第一个假值 或 取D。并不会取true/false。
常写
fn && fn() //如果fn存在就调用fn()
7.2 || 或
A||B||C||D 取按顺序出现的第一个真值 或 取D。并不会取true/false。
常写
A = A || B //A存在就什么也不做,A不存在就取B(B为保底值)
8.循环语句
循环语句用于重复执行某个操作,它有多种形式。
8.1 while 循环
语法:while(表达式){语句}
。
执行顺序:判断表达式的真假,若表达式为真则执行语句,执行完再判断表达式的真假;
若表达式为假,则跳出循环代码块执行循环后面的语句。
代码示例:
var i = 0;
while (i < 10) {
console.log('i 当前为:' + i);
i = i + 1;
}
不要写死循环
死循环举例1:
var a=0.1
while(!a==1){
console.log(a)
a=a+0.1
}
原因:浮点数是不精确的,每次相加后的取值是不精确,所以a一直取不到1。无法跳出循环。
8.2 for 循环
语法:for(语句1;表达式2;语句3){循环体}
执行顺序:
①先执行语句1;
②判断表达式2;
③若真,执行循环体,然后执行语句3;
④若假,直接退出循环,然后执行后面的语句。
代码示例:
var x = 3;
for (var i = 0; i < x; i++) {
console.log(i);
}
// 0
// 1
// 2
特殊举例:
for(var i=0;i<5;i++){
setTimeout(() => {console.log(i)})
}
输出结果:会输出5个5
原因:在循环体i的最后一次值是4,但在跳出循环体后还执行了一次i++,所有结果是5,又因循环5次,所有是5个5。
8.3 do while 循环
不常用。
语法:
do
语句
while (条件);
// 或者
do {
语句
} while (条件);
不管条件是否为真,do...while
循环至少运行一次,这是这种结构最大的特点。另外,while
句后面的分号注意不要省略。
8.4 break 和 continue
break
和continue
语句都具有跳转作用,可以让代码不按既有的顺序执行。
break
是退出所有循环,continue
是退出当前循环,直接下一步。
如果存在多重循环,不带参数的break语句和continue语句都只针对最内层循环。
8.5 label标签
不常用。
JavaScript 语言允许,语句的前面有标签(label),相当于定位符,用于跳转到程序的任意位置,标签的格式如下。
label:
语句
标签可以是任意的标识符,但不能是保留字,语句部分可以是任意语句。
标签通常与break语句和continue语句配合使用,跳出特定的循环。
标签通常与break语句和continue语句配合使用,跳出特定的循环。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) break top;
console.log('i=' + i + ', j=' + j);
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
上面代码为一个双重循环区块,break命令后面加上了top标签(注意,top不用加引号),满足条件时,直接跳出双层循环。如果break语句后面不使用标签,则只能跳出内层循环,进入下一次的外层循环。
标签也可以用于跳出代码块。
foo: {
console.log(1);
break foo;
console.log('本行不会输出');
}
console.log(2);
// 1
// 2
上面代码执行到break foo,就会跳出区块。
continue语句也可以与标签配合使用。
top:
for (var i = 0; i < 3; i++){
for (var j = 0; j < 3; j++){
if (i === 1 && j === 1) continue top;
console.log('i=' + i + ', j=' + j);
}
}
// i=0, j=0
// i=0, j=1
// i=0, j=2
// i=1, j=0
// i=2, j=0
// i=2, j=1
// i=2, j=2
上面代码中,continue命令后面有一个标签名,满足条件时,会跳过当前循环,直接进入下一轮外层循环。如果continue语句后面不使用标签,则只能进入下一轮的内层循环。