原文:https://javascript.info/javascript-specials

本章会简要地列举一下到目前为止我们已经学过的 JavaScript 特性。酒香初上,我们先微醺一下。

代码结构

语句之间使用分号分隔:

  1. alert('Hello'); alert('World');

通常换行也被看做是一个分隔符,所以下面这样写也是可以的:通常也被看做是一个分隔符,所以下面这样写也是可以的:

  1. alert('Hello')
  2. alert('World')

这要归功于 JavaScript 中的“自动分号插入”机制。但有时也有问题:

  1. alert('这条信息关闭后,就会报错的')
  2. [1, 2].forEach(alert)

多数代码风格指南都会建议在每个语句后面加上分号,避免可能出现的报错。

代码块 {...} 后面就不需要加分号了。比如下面列举的函数声明和 for 循环例子:( 或这个像循环这样的语法结构),分号是不需要的:

  1. function f() {
  2. } // 这里不需要加分号
  3. for(;;) {
  4. } // 这里也无需加分号

如果我们在哪个地方多写了个分号也不会报错的,因为它会被忽略。

更多参见:《代码结构》

严格模式

为了能够使用现代 JavaScript 的所有特性,我们最好在脚本顶部使用 "use strict" 声明:

  1. "use strict";
  2. ...

这条声明(或叫“指令”)必须写在脚本代码的顶部,也可以写在函数的顶部。

就是不写 "use strict",代码也能正常运行,但却是以旧的、“兼容的”方式运行的。我们通常更喜欢现代的行为。

像这门语言最近引入的一些特性(比如我们后面要学的类)默认就隐式地启用了严格模式。

译注:这里所谓的“现代 JavaScript ”,是指代码在执行时,不是以旧的、“兼容的”方式运行。这能避免早期过于宽松的代码语法带来的难以理解和调试的困扰。

更多参见:《严格模式》

变量

声明变量可以使用:

  • let

  • const(表示声明常量,用此声明的变量初始化时必须赋值,之后也不能改变)

  • var(旧的声明变量的方式,后面会讲到)

变量名由:

  • 字母和数字组成,但首字符不能是数字。

  • 字符 $_ 跟字母一样,也可以使用。

  • 非拉丁字母和象形文字也是合法的字母,但通常不会使用。

变量的类型是动态的,也就是说一个变量可以储存任意类型的值:

  1. let x = 5;
  2. x = 'John';

一共有七种数据类型:

  • number:包括双精度浮点数和整数,

  • boolean:true/false,

  • string:字符串,

  • null:这个类型里只有一个值 null,代表“空”或者“不存在”,

  • undefined:这个类型里也只有一个值 undefined,代表“没有赋值”,

  • objectsymbol:分别复杂数据结构和唯一标识符,我们还没有学到。

typeof 操作符返回一个值的类型,但有两个:

  1. typeof null == "object" // 这是 JavaScript 的一个 bug
  2. typeof function(){} == "function" // 函数返回的不是 "object",而是 "function"

更多参见:《变量》《数据类型》

交互

我们的工作环境是浏览器,这个宿主环境为我们提供了几个具备简单 UI 界面的交互函数:

prompt(question[, default])

弹出一个包含输入框的弹框,输入框上面显示的是你的问题,输入框里的内容会作为返回值返回。如果用户点击了“取消”,那么返回值为 null

confirm(message)

弹出一个确认框,框内显示的内容是你调用时使用的 message。如果用户点击了“确认”,返回值是 true;点击“取消”的话,返回值是 false

alert(message)

弹出一个消息框,框内显示的内容是你调用时使用的 message。点击“确定”即可关闭弹窗。

所有这些交互函数都是以模态窗的形式出现的,当这些窗口弹出时,会暂停当前代码的执行,除非用户应答,否则操作不了页面的其他部分。

例如:

  1. let userName = prompt("Your name?", "Alice");
  2. let isTeaWanted = confirm("Do you want some tea?");
  3. alert( "Visitor: " + userName ); // Alice
  4. alert( "Tea wanted: " + isTeaWanted ); // true

更多参见:《交互函数:alert、prompt 和 confirm》

运算符

JavaScript 支持下列这些运算符:

算术

除了常规的 +-*/,还有取模运算符 % 和求幂运算符 **

两元加运算符可以用来连接字符串。如果其中一个操作数是字符串,那么另一个会被转为字符串:

  1. alert( '1' + 2 ); // '12' 是个字符串
  2. alert( 1 + '2' ); // '12' 是个字符串

赋值

举两个例子:简单赋值语句:a = b,以及复合赋值语句:a *= 2

位运算符处理最底层的、32位整数级别上的运算。以后用到时候,查下文档就行了。

条件

这是唯一一个包含三个参数的运算符:cond ? resultA : resultB。如果 cond 是真值,就返回 resultA,否则返回 resultB

逻辑

逻辑运算符与 && 和或 || 都属于短路求值,返回值就是运算终止时停留在的那个操作数(就是说返回值不一定是 true/false)。逻辑非 ! 运算符会将操作数转换为布尔,然后取反,最后返回。

比较

当相等运算符 == 两边的值是不同类型的时,会转换为数值进行比较(nullundefined 除外,它们彼此相等,与其他值比较是都不等)。因此,下列的比较结果返回 true

  1. alert( 0 == false ); // true
  2. alert( 0 == '' ); // true

其他的比较运算符也遵循这一转换规则。

值得注意的是,严格相等运算符 === 不发生类型转换。对于它来说,不同类型就意味着不相等。

nullundefined 稍微特殊点:用 == 比较它们时,得到的是 true,但与其他值比较就是 false

当大于/小于运算符两边都是字符串时,使用的是另一个比较规则:会逐个字符比较字符串,比较的实际是字符底层的 Unicode 码点的大小;其他情况,都会将运算数转换成数字后再比较。

其他的

除此之外,还有像逗号运算符在内的其他的运算符。

更多参见:《运算符》《比较运算符》《逻辑运算符》

循环

  • 我们讲了三种循环语法。
  1. // 1. while 循环
  2. while (condition) {
  3. ...
  4. }
  5. // 2. do { ... } while 循环
  6. do {
  7. ...
  8. } while (condition);
  9. // 3. for 循环
  10. for(let i = 0; i < 10; i++) {
  11. ...
  12. }
  • for(let ...) 中声明的变量,只在循环体内才可以访问,但是我们也可以忽略 let 然后重用已经存在的变量。

  • break/continue 关键字用来退出循环/忽略当前迭代、进入下一次迭代。使用 label 关键字则可以实现嵌套循环时,跨循环 break、continue 的功能。

更多参见:《while、for 循环》

后面我们还会学到其他的循环语法,可以用来循环对象。

switch 语句

switch 语句可以用来替换多分支 if 判断。内部呢,是使用严格相等运算符 === 来做比较的。

例如:

  1. let age = prompt('你多大啦?', 18);
  2. switch (age) {
  3. case 18:
  4. // prompt 返回的结果字符串, 不是数值,所以不会执行这个分支判断
  5. alert('不会执行这个分支判断');
  6. case '18':
  7. alert('而会执行这个分支判断');
  8. break;
  9. default:
  10. alert('如果 `age` 不是数值 18 也不是字符串 "18",就会执行这个分支判断');
  11. }

更多参见:《switch 语句》

函数

我们介绍了三种创建函数的方式:

  1. 函数声明:在主代码流(main code flow)中出现的函数
  1. function sum(a, b) {
  2. let result = a + b;
  3. return result;
  4. }
  1. 函数表达式:在表达式中出现的函数
  1. let sum = function(a, b) {
  2. let result = a + b;
  3. return result;
  4. }
  1. 箭头函数
  1. // 作为表达式右值
  2. let sum = (a, b) => a + b;
  3. // 如果函数里有多行语句,就要使用花括号 { ... }, 还要有 return:
  4. let sum = (a, b) => {
  5. // ...
  6. return a + b;
  7. }
  8. // 没有参数的情况
  9. let sayHi = () => alert("Hello");
  10. // 有一个参数
  11. let double = n => n * 2;
  • 函数可以有局部变量:在函数里声明,也只能在函数里才能访问到。

  • 参数可以有默认值:function sum(a=1, b=2) {...}

  • 函数总是有返回值。如果函数里没有写 return,默认返回值是 undefined

更多参见:《函数》《函数表达式和箭头函数》

还有更多

这里只是简要地列举了到目前为止我们已经学过的 JavaScript 特性,这些都是基础。以后,我们还会学到更多、更高级的 JavaScript 特性。

(完)