JavaScript 语法

314 阅读5分钟

1 语句和表达式

  • 语法(grammar)
  • 词法(syntax)

1.1 表达式与语句

  1. 语句相当于句子,表达式相当于短语,运算符则相当于标点 符号和连接词。

  1. 语句都有一个结果值。
  • 赋值表达式b = a,结果值是赋给b的值;
  • 规范定义var的结果值是undefined。var a = 42; 结果值 undefined,而非 42。
  • 代码块 { .. } 的结果值是其最后一个语句 / 表达式的结果。代码块的结果值就如同一个隐式的返回,即返回最后一个语句的结果值。
  • 语法不允许我们获得语句的结果值并将其赋值给另一个变量。

  • 获取语句结果值:eval-不要这样做! 或者ES7的do

1.2 表达式副作用

  • 大部分表达式没有副作用。函数调用可能有副作用。

  • 可以把 ++ --理解成副作用

  • 括号无法清除++的副作用

  • 使用逗号运算符,可以间接消除++的副作用

1.3 上下文规则

  • 大括号定义对象常量

  • 标签
// 假定函数bar()已经定义
{
    foo: bar()
}
    
错误的看法:这里的 { .. } 是一个孤立的对象常量,没有赋值
正确: { .. }在这里只是一个普通的代码块。foo 是语句 bar() 的标签。

// 标签为foo的循环
foo: for (var i=0; i<4; i++) {
for (var j=0; j<4; j++) {
    // 如果j和i相等,继续外层循环
    if (j == i) {
        // 跳转到foo的下一个循环
            continue foo;
    }
    // 跳过奇数结果
    if ((j * i) % 2 == 1) {
        // 继续内层循环(没有标签的)
        continue; 
    }
    console.log( i, j ); }
}
// 1 0
// 2 0
// 2 1
// 3 0
// 3 2
  • contine foo并不是指“跳转到标签foo所在位置继续执行”,而是“执行 foo 循环的下一轮循环”。所以这里的 foo 并非 goto。
  • break foo不是指“跳转到标签foo所在位置继续执行”,而是“跳出标签 foo 所在的循环 / 代码块,继续执行后面的代码”。因此它并非传统意义上的 goto。
  • {"a":42} 这样的 JSON 字符串会被当作合法的 JavaScript 代码(请注意 JSON 属性名必须使用双引号!)。其实不是!如果在控制 台中输入 {"a":42} 会报错。
  • 因为标签不允许使用双引号,所以"a"并不是一个合法的标签,因此后面不能带 :。
  • JSON 的确是 JavaScript 语法的一个子集,但是 JSON 本身并不是合法的 JavaScript 语法。 比如{"a":42} 作为 JSON 值或者参数没有任何问题,但是在作为代码执行时会产生错误。
  • JSON-P 能将 JSON 转换为合法的 JavaScript 语法。

1.4 代码块

1.5 else if

JavaScript中没有else if!!!

实际是代码检查会认为它是 else{if{}}

JavaScript 代码检查工具建议对单条语句也应该加上 { }

2 运算符优先级

  • ++ -- 优先级最低
  • &&运算符的优先级高于 =
  • && 运算符先于 || 执行
  • || 的优先级高于 ? :
  • && 和 || 会短路,有结果即返回

3 自动分号

  • 有时 JavaScript 会自动为代码行补上缺失的分号,自动分号插入(Automatic SemicolonInsertion,ASI)。
  • ASI 只在换行符处起作用,而不会在代码行的中间插入分号。
  • 如果 JavaScript 解析器发现代码行可能因为缺失分号而导致错误,那么它就会自动补上分号。——不致命不加
  • 并且,只有在代码行末尾与换行符之间除了空格和注释之外没有别的内容时,它才会这样做。
  • 语法规定 do..while 循环后面必须带分号,而 while 和 for 循环后则不需要
  • 语句代码块结尾不用带 ;
  • break、continue、return 和 yield(ES6)等关键字需要加;
  • 因为return会自动加; 所以想要跨行的话,return后面的内容要加()

4 错误

  • 早期错误:在编译阶段发现的错误,比如语法错误。无法用 try..catch 来捕获的,会导致解析/编译失败
  • 运行时错误:TypeError、ReferenceError、SyntaxError等

5 函数

在 ES6 中,如果参数被省略或者值为 undefined,则取该参数的默认值。

5.1 try...finally

  • 在 try 之后执行,如果有 catch 的话则在 catch 之后执行。
  • 可以将 finally 中的代码看作一个回调函数,即无论出现什么情况最后一定会被调用。
  • 如果 finally 中抛出异常(无论是有意还是无意),函数就会在此处终止。如果此前 try 中 已经有 return 设置了返回值,则该值会被丢弃。
  • yield,可视为return 的中间版本。然而与 return 不同的是,yield 在 generator重新开始时才结束,这意味着try { .. yield .. }并未结束, 因此 finally 不会在 yield 之后立即执行。
  • finally 中的 return 会覆盖 try 和 catch 中 return 的返回值。
  • 通常来说,在函数中省略return的结果和return;及return undefined;是一样的,但是 在 finally 中省略 return 则会返回前面的 return 设定的返回值。

5.2 swicth

  • 如果匹配就执行该 case 中的代码,直到 break 或者 switch 代码块结束。
  • a 和 case 表达式的匹配算法是===
  • 首先遍历并找到所有匹配的 case,如果没有匹配则执行default中的代码。如果default中没有break,所会继续执行已经遍历过的case 3代码块,直到break为止。