阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      第 2 章 语法结构 学习笔记

      第 2 章: 语法结构

      语法是一门编程语言的基础,用来描述这门语言是如何使用的,作为语言的基础,它规定了变量是什么样子的,注释怎么写,两段语句之间如何分割,本章用很短的篇幅来介绍它们。

      • 区分大小写,空格,换行符
      • 注释
      • 字面量
      • 标识符和保留字
      • Unicode 转义
      • 可选的分号

      2.1 区分大小写

      JavaScript 这门语言是区分大小写的,也就是说关键字,变量,函数名和所有标识符都需要严格的使用原本的拼写,不能改变其中任何一个字符。比如关键字 while 必须写成 while,除此以外的任何拼写都是不对,如果写成 WhileWHILE就是错误的。同样的原理, online , Online , OnLine , and ONLINE 是代表四个不同的变量名,不要混淆使用。

      JavaScript 代码之间可以使用任意个空格和换行符进行分割,为了代码的可读性,我们一般会通过缩进和换行来实现统一的代码风格。

      除了普遍的空格符 (\u0020)以外,JavaScript 还可以用制表符(按Table键),ASCII,Unicode空格来控制代码风格。JavaScript 会将换行符,回车识别为结束的符号。

      2.2 注释

      JavaScript 支持两种注释方式:

      • //
        • 双斜线之后的所有内容都被被识别为注释
        • 这种注释方式因为只对单行有效果,所以也叫单行注释
      • /**/
        • /**/ 之间的内容,都会被当作注释
        • 这种注释方式可以用在多行,所以也叫多行注释
        • 注意:多行注释不能嵌套使用

      下面都是合法的注释

      // 这是单行注释
      /* 这是多行注释,也可以用于单行 */ // 这是另外一段是注释
      /*
       * 这是多行注释,开头的 * 是非必需的,仅仅是为了让注释看起来更加美观和易读
       * 多行注释可以横跨多行
       */
      

      2.3 字面量

      所谓的字面量,就是程序中直接使用的数据,下面都是字面量:

      12              // 数值
      1.2             // 小数,也有叫浮点数
      "hello world"   // 字符串
      'Hi'            // 字符串
      true            // 布尔值
      false           // 布尔值
      null            // 空值  这个字面量在中文交流时,建议直接用英文的 null 进行交流
      

      关于数字和字符串的更多说明,请参考第三章。

      2.4 标识符和保留字

      标识符仅仅只是一个名字, 在JavaScript中,标识符用于对常量,变量,属性,函数和类进行命名,或者作为循环中的跳转标记。标识符只能以字母,下划线(_)或美元符号($)开始。 后面可以跟字母,数字,下划线或美元符号(重点:数字不能放在标识符的第一位)。

      下面都是合法的标识符:

      i
      my_variable_name
      v13
      _dummy
      $str
      

      和其它语言一样,JavaScript保留了一些标识符为语言自身使用,下一节中介绍的字符,我们是不能使用的。

      2.4.1 关键字和保留字

      下面列出的单词是 JavaScript 这门语言自身的一部分。其中许多是保留关键字,不能用作常量,变量,函数或类的名称(比如 if,while,for,但它们都可以用作对象的属性)。还有一些是在在特殊情况下可以使用的,但是我们写代码的时候没有必要冒险,要尽量避免使用下面的单词作为标识符:

      关键字

      var     let         const
      typeof  instanceof
      true    false       null
      if      else        for         in      of          while       do
      switch  case        continue    break
      async   await
      new     function    this        return  yield       void        default
      try     catch       finally     throw   debugger
      export  import      as          class   extends     super       static
      get     set         delete
      with    from        target
      

      JavaScript还保留了一些单词供未来使用,这些单词目前还没有被启用,但是未来可能会使用。我们平时写代码的时候,尽量避免使用。

      保留字

      enum implements interface package private protected public
      

      由于历史原因,argumentseval 在某些情况下不允许用作标识符,最好完全避免将他们作为标识符。

      2.5 Unicode

      首先介绍一下 Unicode 的概念: Unicode(又称统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。我们现在使用的中文在计算机中就是以 Unicode 的形式存在的。

      比如基本中文汉字在 Unicode 中的范围是 u4E00-u9FA5,如果我们需要判断用户输入的内容必须为中文,就可以参考下面这个正则;

      let pattern = /^[\u4e00-\u9fa5]+$/;     // 内容必须是中文
      console.log(pattern1.test('朱安邦'));   // true
      console.log(pattern1.test('朱安邦1'));  // false
      

      回到正题,JavaScript 程序是使用 Unicode 字符集编写的,您可以在标识符,字符串,注释中使用任意 Unicode 字符。为了维护方便,通常在标识符中仅使用 ASCII 字母和数字。

      这仅仅只是一种编程规范,如果你愿意,你完全可以在在标识符中使用任何 Unicode 字母,数字和文字(但不包括 Emoji 标枪)。比如使用中文作为变量名,这是合法的。

      const π = 3.14;
      const  = true;
      const 朱安邦 = '朱安邦是一个人名';
      

      2.5.1 Unicode 转义序列

      有些老旧的计算机硬件和古老软件无法正常的显示,输入和处理完整的Unicode字符集。为了支持老旧系统和程序员的工作,JavaScript 定义了转义序列,使我们可以仅使用 ASCII 字符就能编写 Unicode 字符。

      这些 Unicode 转义以 \u 为前缀,后面紧跟四个十六进制数(合法的十六进制数有: 数字,大写或小写的 A–F 字母)。

      您可以在标识符(不能是关键字),字符串,注释中使用任意 Unicode 字符。

      下面是三种方式写 café 这个变量。

      let café = 1;           // 使用 Unicode 字符定义变量
      caf\u00e9               // => 1; 使用转义序列访问变量
      caf\u{E9}               // => 1; 相同转义序列的另一种形式
      
      'café' === 'caf\u00e9'  // => true
      'café' === 'caf\u{E9}'  // => true
      

      JavaScript 的早期版本仅支持四位数的转义序列。

      为了支持更多的 Unicode,在 ES6 版本中引入了带有花括号的写法。例如我们写 Emoji 表情符号:

      console.log("\u{1F600}"); // => 😀 输出一个笑脸表情
      

      Unicode 转义也可能出现在注释中,但是由于注释是属于被忽略的文本,它们不会被解析;所以它们在注释中仅仅被当作 ASCII 的字符本身。

      2.5.2 Unicode 标准

      如果在 JavaScript 程序中使用非 ASCII 字符,则需要注意 Unicode 支持使用多种方法对同一字符进行编码。例如,字符串 "é" 可以使用字符 \u00E9 来表示,也可以使用普通的 ASCII 字符 "e" 加声调符 \u0301。这两种方式在渲染的时候看起来完全相同,但它们的二进制编码完全不同,这意味着 JavaScript 会把他们当作两个标识符进行处理,如果你不注意这些,可能导致你的代码出现BUG:

      请是试一试下面的例子,

      const café = 1;     // 名字是 "caf\u{e9}"
      // const café = 2;     // 名字是 "caf\u{301}"
      caf\u{e9};          // => 1; 
      cafe\u{301};        // VM303:1 Uncaught ReferenceError: café is not defined
      'café' === 'café';              // => false
      'caf\u{e9}' === 'cafe\u{301}';  // => false
      

      如果打算在 JavaScript 程序中使用 Unicode 字符,应确保编辑器以标准的方式渲染 Unicode 字符,防止因为视觉上无法区分标识符导致书写混乱。也可以复制该 Unicode 字符,在编辑器里搜索,查看能够检索到对应的标识符。

      2.6 可选的分号

      像许多编程语言一样, JavaScript 使用分号(;)来进行多条语句的分隔(请参见第五章)。分号会使代码的可读性更高:在JavaScript中,如果两条语句分别独占一行,通常可以省略两个语句之间的分号。(代码结尾的分号可以省略,右花括号 “}” 之前的分号可以省略。)

      JavaScript 程序员主要分为两种代码风格

      • 一种是尽可能的使用分号来标记语句的结束。
      • 一种是尽可能的省略分号,只有在不得不用的时候才写分号。

      无论您选择哪种风格,您都应该了解一下关于 JavaScript 中的分号使用细节。

      下面的代码,由于这两条语句分别独占一行,因此可以省略第一个分号,省略后,JavaScript 会在换行处隐式的填补分号:

      a = 3;
      b = 4;
      

      如果按照下面的格式写代码,第一个分号是不能省略的:

      a = 3; b = 4;
      

      JavaScript 不会在每个换行处都隐式的填补分号,只有在不隐式添加分号就无法解析代码的情况下,它才会将换行符视为分号。用书面的方式说,就是如果当前字符和随后的非空字符不能当作一个整体来解析的话,JavaScript 就会将换行符视为分号(或者理解为隐式的补一个分号)。

      let a
      a
      =
      3
      console.log(a)
      

      JavaScript 会把上面的代码解析如下:

      let a; a = 3; console.log(a);
      

      JavaScript 在第一个换行符处隐式加了分号,因为不加分号,它就无法继续解析代码了。

      第二个 a 原本可以当作一条单独的语句 a; 进行解析;因为 JavaScript 可以把它和后面的 = 3 继续解析成 a = 3;,所以这里就不会解析成a;

      解析规则: “只要 JavaScripr 能够继续往下解析,就不会在该处隐式的添加分号”。

      根据这种规则,也会导致一些意想不到的情况,比如下面这段代码,写在两行,看起来是两条独立的语句;

      let y = x + f
      (a+b).toString()
      

      But the parentheses on the second line of code can be interpreted as a function invo‐ cation of f from the first line, and JavaScript interprets the code like this:

      但是根据上面总结的解析规则,第二行代码的括号,可以作为第一行结尾 f 的函数调用,也就是说可以解析为 f(a+b),所以最终 JavaScript 会上面的代码,解析成下面这个鬼样子:

      let y = x + f(a+b).toString();
      

      解析成这个样子,很可能就不是作者想要的效果了。

      如果作者是将他们当作一条语句进行解析,为了代码规范,需要改成下面这个样子,不应该使用换行符;

      let y = x + f(a+b).toString();
      

      如果是将它们作为两条单独的语句进行解析,此处需要写一个分号进行分割,这里的分号一定不能省略;

      let y = x + f;
      (a+b).toString()
      

      通常,如果一条语句以 (, [, /, +, 或 - 开头,它非常有可能和前一条语句解析成一条语句;

      实际上,以 /+- 开头的语句并不多,但是以 (, [ 开头的语句非常的常见。

      有些程序员喜欢保守的在语句前加一个分号,这样做的好处是: 即使前一条语句被修改了,分号被删除了,当前的语句还是可以正常的进行解析;

      let x = 0 // 此处省略了分号
      ;[x,x+1,x+2].forEach(console.log) // 前面的分号; 将此语句和上面进行分开
      

      三种例外情况

      如果 JavaScript 不能将第二行代码解析为第一行语句的延续时,通常情况下会隐式的补一个空格;

      但是下面三种情况例外,这些语句通常是独立的:

      • 第一种: returnthrowyieldbreakcontinue 语句
        • 如果在这些单词之后出现换行符,JavaScript 会始终将该换行符解释为分号。
      • 第二种: ++-- 运算符
      • 第三种: => 箭头函数本身

      第一种:

      return
      true;
      

      JavaScript 会把上面的代码解析如下:

      return; true;
      

      而代码的本意是下面这个样子的:

      return true;
      

      这意味着您不能在 returnbreakcontinue 关键字和后面表达式之间使用换行符。如果您用换行符将他们隔开;只要代码能够正常解析,程序不会报错,这种不会报错的 Bug 调试起来非常的不方便。

      第二种:

      第二种是 ++-- 运算符(详情参考第4.8节)。因为这些运算符既可以放在在表达式之前,也可以放在在表达式之后。比如下面的使用方法都是正确的;

      i++;
      ++i;
      
      j--;
      --j;
      

      向上面 return 的例子一样,如果要用自增和自减,则它们必须与它们所要用的表达式放在同一行上。

      比如下面的代码;

      let x =1;
      let y=2;
      
      x
      ++
      y
      console.log(x);// => 1
      console.log(y);// => 3
      
      x
      --
      y
      console.log(x);// => 1
      console.log(y);// => 2
      

      会解析为

      let x =1;
      let y=2;
      
      x; ++y;
      console.log(x);// => 1
      console.log(y);// => 3
      
      x; --y;
      console.log(x);// => 1
      console.log(y);// => 2
      

      注意:是解析为 x; ++y;, 而不是 x++; y

      第三种:

      使用简洁的"箭头"语法定义的函数,=> 参数必须和箭头本身在同一行。

      比如下面的代码就是错误的

      const ary = [
          'zhu',
          'an',
          'bang'
      ];
      
      console.log(
          ary.map(
              item
                  =>
                  item.length
          )
      );
      

      要把参数和箭头放在一行才可以 :

      const ary = [
          'zhu',
          'an',
          'bang'
      ];
      
      console.log(
          ary.map(
              item =>
                  item.length
          )
      );
      

      2.7 小结

      本章介绍了 JavaScript 程序的基本使用规则。下一章我们将继续向后讲解,下一章介绍原始类型和值(数字,字符串等),它们是JavaScript程序的最小数据单位。

      目录
      目录