Error 对象

当代码运行时发生错误,会立刻中止当前 JavaScript 的执行,同时会创建新的 Error 对象,并将其抛出( throw )

错误类型:

  • SyntaxError 语法错误,当 JavaScript 引擎在解析代码时,如果遇到不符合语法规范的 tokens 或 token顺序时,就会抛出 SyntaxError

    例:

    1
    2
    3
    console.log([) //SyntaxError: Unexpected token ')'
    var = 1; //SyntaxError: Unexpected token '='
    { //SyntaxError: Unexpected end of input
  • ReferenceError 引用错误,当一个不存在的变量被引用时发生的错误

    例:

    1
    2
    3
    4
    5
    //访问未声明的变量
    console.log(author); //ReferenceError: b is not defined
    //给函数调用表达式赋值
    function fun(){}
    fun() = 123; //ReferenceError: Invalid left-hand side in assignment
  • RangeError 范围错误,当一个值不在其所允许的范围中时则抛出该错误

    例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    //数组长度为负数
    [].length = -1; //RangeError: Invalid array length
    //Number 对象的方法参数超出范围
    const num = new Number(12.34);
    console.log(num.toFixed(-1)); //RangeError: toFixed() digits argument must be between 0 and 20 at Number.toFixed
    //调用栈超过最大值
    function foo(){
    foo()
    }
    foo(); //RangeError: Maximum call stack size exceeded
  • TypeError 类型错误,值的类型或参数不是预期类型时发生的错误

    例:

    1
    2
    3
    4
    5
    //调用不存在的方法
    const person = {};
    person.run(); //TypeError: person.run is not a function
    //new 操作符后面不是构造函数
    const instance = new 2(); //TypeError: 2 is not a constructor
  • URIError URI错误,使用全局 URI 处理函数而产生的错误

    例:

    1
    2
    decodeURI("%"); //URIError: URI malformed
    decodeURIComponent("%"); //URIError: URI malformed

自定义错误

例:

1
2
3
4
5
6
7
8
9
function DiyError(message) {
// 定义错误类型消息
this.message = message || '默认信息';
// 定义错误类型名称
this.name = 'DiyError';
}

UserError.prototype = new Error();
UserError.prototype.constructor = DiyError;

上面代码自定义一个错误对象DiyError,让它继承Error对象。然后,就可以生成这种自定义类型的错误了

1
2
// 抛出一个 DiyError 类型错误
throw new DiyError('这是自定义的错误!');

PS:throw语句的作用是手动中断程序执行,抛出一个错误

try…catch 语句

一旦发生错误,程序就中止执行了。JavaScript 提供了try...catch语句,允许对错误进行处理,选择是否往下执行

例1:

1
2
3
4
5
6
7
8
9
10
11
try {
throw new Error('出错了!');
} catch (error) {
// error 为错误类型对象
console.log(error.name + ": " + error.message); // Error: 出错了!
// e.stack 调用栈信息,用于定位错误代码位置
console.log(error.stack);
} finally {
// finally 块最后执行,可以省略
console.log('最后执行');
}

在 try 块中的代码,发生错误时,会立即执行 catch 块中的代码,并将发生错误的错误对象作为 catch 块的参数传递( 可以省略 ),你可以在 catch 块中决定是否让程序继续执行。而 finally 块中的代码会在 catch 块执行结束后执行,用于做一些资源清理操作

例2:

1
2
3
4
5
6
7
8
9
10
11
try {
foo.bar();
} catch (e) {
// 根据不同的错误类型去执行不同的操作
if (e instanceof EvalError) {
console.log(e.name + ": " + e.message);
} else if (e instanceof RangeError) {
console.log(e.name + ": " + e.message);
}
// ...
}

严格模式

在ES5中增加了一种运行模式,即严格模式(strict mode),该模式可以使JavaScript在更严格的条件下运行

严格模式的目的:

  1. 消除 Js 语法的一些不合理、不严谨之处,减少一些怪异行为
  2. 消除代码运行的一些不安全之处,保证代码运行的安全
  3. 提高编译器效率,提升执行速度
  4. 为未来新版本的 JavaScript 做好铺垫

开启严格模式

通过 "use strict" 这个特殊语句来开启严格模式

语法:

1
2
3
4
"use strict"

'use strict'
// "use strict" 语句可作用与全局和函数(作用域)

开启严格模式后的变化

1.禁止意外创建全局变量

在非严格模式中,如果一个变量没有声明就赋值,默认是全局变量。严格模式禁止这种用法

例:

1
2
3
4
5
6
7
8
9
10
11
12
13
function fn() {
a = 200;
console.log(a); // 200
}
fn();
console.log(a); // 200
"use strict"; //开启严格模式
function fn2() {
w = 200;
console.log(w); //抛出异常,w is not defined
}
fn2();
console.log(w); //抛出异常,w is not defined

2.静默失败(不报错也没生效)转为抛出异常

例1:

1
2
3
4
/* 在非严格模式下为只读属性赋值 */
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // 静默失败
1
2
3
4
5
/* 在严格模式下为只读属性赋值 */
"use strict";
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, writable: false });
obj1.x = 9; // 抛出 TypeError 错误

例2:

1
2
3
4
/* 在非严格模式下为不可扩展对象的新属性赋值 */ 
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // 静默失败
1
2
3
4
5
/* 在严格模式下为不可扩展对象的新属性赋值 */
"use strict";
var fixed = {};
Object.preventExtensions(fixed);
fixed.newProp = "ohai"; // 抛出 TypeError 错误

例3:

1
2
3
4
5
6
/* 在非严格模式下使用 delete 运算符未删除成功 */
var x;
delete x; // 静默失败
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, configurable: false });
delete obj1.x; // 静默失败
1
2
3
4
5
6
7
/* 在严格模式下使用 delete 运算符未删除成功 */
"use strict";
var x;
delete x; // 抛出 SyntaxError 错误
var obj1 = {};
Object.defineProperty(obj1, "x", { value: 42, configurable: false });
delete obj1.x; // 抛出 TypeError 错误

3.禁止函数中出现重复的参数名

例:

1
2
3
4
5
/* 非严格模式 */
function sum(a, a, c) {
return a + a + c; // 3 + 3 + 4
}
sum(2, 3, 4) // 10
1
2
3
4
5
6
/* 严格模式 */
function sum(a, a, c) {
"use strict";
return a + a + c; // 这里会出错
}
sum(2, 3, 4)

4.禁止使用八进制数字(0开头)

例:

1
2
3
"use strict"
var b = 010 // 抛出 SyntaxError 错误
//可以使用ES6中新增的 0o 开头来表示八进制

5.禁止将 eval 作为标识符

eval() 是全局对象中的方法,作用是将一个字符串作为 Js 代码执行,如:eval("var a = 666;console.log(a)"),在严格模式中 eval 不能作为标识符

例:

1
2
3
4
/* 非严格模式 */
var eval = 17; // 正常声明
eval("var a = 666");
console.log(a); // 666
1
2
3
4
5
6
/* 严格模式 */
"use strict"
var eval = 17; // 抛出 SyntaxError 错误
eval("var a = 666; console.log(a)"); // 666
console.log(a) //抛出异常,a is not defined
//变量 a 只在 eval() 作用域内有效

6.禁止将 arguments[i] 赋值给实参或实参赋值给 arguments[i]

在严格模式中 arguments 不能作为标识符

例:

1
2
3
4
5
6
function f(a) {
"use strict";
a = 42;
return [a, arguments[0]];
}
console.log(f(17)); // [42, 17]

7.禁止使用 arguments.callee() 方法

例:

1
2
3
4
5
"use strict";
function f() {
return arguments.callee;
};
f(); // 抛出类型错误

8.严格模式中函数中的 this 默认值为 undefined

例:

1
2
3
4
function fn(){
"use strict"
console.log(this); // undefined
}

9.允许通过函数的call()、apply()、bind()方法将函数中 this 的值指定为 null 或 undefined(任何值)

1
2
3
4
5
6
7
8
9
10
11
/* 未开启严格模式 */
function fn(){
console.log(this); // window
}
fn.call(null);
/* 开启严格模式 */
function fn2(){
"use strict"
console.log(this); // null
}
fn2.call(null);

10.标示符的限制

未来版本的 ECMAScript 很有可能会引入新语法,ECMAScript5 中的严格模式就提早设置了一些限制来减轻之后版本改变产生的影响

在严格模式中一部分字符变成了保留的关键字。这些字符包括implements, interface, let, package, private, protected, public, staticyield。在严格模式下,你不能再用这些名字作为变量名或者形参名