JavaScript中存在着自动补上分号的行为,即自动分号插入(缩写ASI)
ASI只在换行处起作用,而且只有在代码行末尾只有空格或注释的时候才会自动补上分号
//不会自动补分号
var a,
b
//会自动补分号
var a
b
JavaScript中规定do..while后面必须带分号,而while和for循环则不需要
这时候ASI就非常有用了
此外还需要注意的是break,continue,return,和yield(ES6)等关键字也会在后面补分号
所以换行的时候需要格外考虑是否ASI是否会对代码逻辑产生影响
function fun1() {
return
1 + 1
}
fun1() //undefined
function fun2() {
return 1 + 1
}
fun2() //2
JavaScript中的错误除了运行时错误(TypeError,ReferenceError,SyntaxError等)
还有一些编译时错误
这些编译阶段发现的代码错误叫做早期错误
语法错误是早期错误中的一种,不仅局限于语法错误,还包括语法正确但不符合语法规则的错误
比如正则表达式中的语法错误但是JavaScript语法正确也会产生早期错误
语法规定赋值对象必须是一个标识符(或者ES6中的结构表达式)
因此以下情况会报错
var a;
42 = a;
ES5的严格模式还定义了很多早期错误
比如函数参数不能同名
function foo(a, b, a) {} //没问题
function foo(a, b, a) { "use strict" } //错误!
从语义角度考虑,这些错误在词法上是正确的,但是语法上是错误的,由于没有GrammarError类型,一些浏览器就用SyntaxError来代替
ES6规范定义了一个新概念,叫TDZ
TDZ指的是由于代码中的变量还没有初始化而不能被引用的情况
例如
{
a = 2; //ReferenceError
let a;
}
a = 2试图在let a初始化 a 之前使用该变量(作用域在{}中),这里({..}中到let a前的区域)就是a的TDZ
注意,typeof的安全机制(具体介绍JavaScript 学习笔记 之 类型) 在TDZ中无用,但对未声明的变量依然有用
{
typeof a; //ReferenceError
typeof b; //undefined
let a;
}
另一个TDZ违规的例子是ES6中的参数默认值
(function(a = 1, b = b + a) {})(); //Uncaught ReferenceError: b is not defined
这个例子中,b=b+a(=右边的b)刚好在b的TDZ中访问了b,因此触发了错误
而访问a则没问题,此时刚好跨出了a的TDZ
在ES6中,如果参数被省略或者值为undefined,则取该参数的默认值,但是参数值为undefined,依然会在arguments数组中
function fun(a = "a", b = "b") {
console.log(a, b, arguments);
}
fun(1, 2); //1 2 [1,2]
fun(undefined); //a b [undefined]
向函数传递参数时,arguments数组中对于单元会和对应命名参数建立关联已得到相同的值
function fun(a) {
a = "linked";
console.log(arguments[0]);
}
fun("a"); //linked
fun(undefined); //linked
fun(); //undefined
但是在严格模式下不存在关联
function fun(a) {
"use strict";
a = "linked";
console.log(arguments[0]);
}
fun("1"); //1
fun(undefined); //undefined
fun(); //undefined
finally中的代码总是在try之后执行,如果有catch的话则在catch之后执行
可以吧finally中的代码看做是一个回调函数,即无论什么情况最后一定会调用
即使try中已经return了,finally中的代码还是会执行,而且如果finally中有return,则会覆盖之前return的值
function fun() {
try {
return "try";
} finally {
console.log("finally");
}
console.log("never run");
}
console.log(fun()); //finally try
这里先执行 return 并将返回值设置为 try 然后执行完finally ,函数才算执行完毕返回"try"值(
try中出现了throw也是一样,先执行完finally后再抛出错误
但是如果finally中抛出异常的话函数就会在此处终止,如果之前try中有返回值,这个返回值会被丢弃
continue和break也是一样,执行完continue在i++之前会先执行finally中的代码块
ES6中的yield有些特别
与return不同的是,yield在generator重新开始时结束
function* fun() {
try {
yield "try";
} finally {
throw "over";
}
}
var gen = fun();
console.log(gen.next()); //{value: "try", done: false}
console.log(gen.next()); //Uncaught over
事实上还可以将finally和带标签的break混合使用
function fun() {
bar: {
try {
return "try";
} finally {
break bar;
}
}
return "break";
}
console.log(fun()); //break
switch可以看做是if..else if..else的简化版本
switch (a){
case value:
break;
default:
break;
}
运行时会用a和value进行一个===比较
因此必要时我们可以进行一些特殊处理来进行==比较(即通过强制类型转换进行相等比较)
switch(true) {
case !!(a == value):
break;
default:
break;
}