基础篇:Error、JSON、Math、console 对象

这四个全局对象分别管异常、数据交换、数值计算和调试输出。日常业务几乎都会碰到,但各自的边界(什么能序列化、什么会抛错、控制台方法到底打印什么)经常被混用。

Error 对象

通过 Error 的构造器可以创建一个错误对象。代码运行出错时,引擎会创建 Error 对象并抛出。自定义异常也可以把 Error 当作基类。

new Error(message)
new Error(message, options)          // options.cause 为 ES2022 错误链
new Error(message, fileName, lineNumber) // fileName、lineNumber 仅 Firefox 等非标准参数

message 是人类可阅读的错误描述信息。

options.cause(可选)用于挂上更底层的原始错误,便于链式排查。

fileNamelineNumber(非标准)是被创建的 Error 对象的文件名和行号,默认指向调用 Error 构造器的位置。

try {
    throw new Error("MyError!");
} catch (e) {
    console.log(e.message); // 'MyError!'
    console.log(e.name);    // 'Error'
    console.log(e.stack);   //  'Error: MyError! at...'。实现广泛支持,规范长期未统一
}

Error 可能当作普通函数一样使用,返回一个 Error 对象,与通过 new 关键字构造 Error 对象生成的结果相同。

Error 类型

  • EvalError: 规范里与 eval() 相关。现行引擎对非法 eval 代码通常抛 SyntaxError,业务里很少再见到 EvalError
  • InternalError: 非 ECMAScript 标准(Firefox 曾用于「递归太深」等引擎内部错误)。
  • RangeError: 数值变量或参数超出其有效范围。如:数组长度为负数、Number 对象的方法参数超出范围、函数堆栈超过最大值。
  • ReferenceError: 引用一个不存在的变量时发生的错误。
  • SyntaxError: 解析代码的过程中发生的语法错误。
  • TypeError: 变量或参数不属于有效类型。
  • URIError: URI 相关函数的参数不正确时抛出的错误。主要涉及:encodeURI()decodeURI()encodeURIComponent()decodeURIComponent()。历史上的 escape()unescape() 已废弃,不要再用于新代码。

自定义异常类型

class MyError extends Error {
    constructor(message) {
        super(message);
        this.name = 'MyError';
    }
}

try {
    throw new MyError('custom message');
} catch (e) {
    console.log(e.name);    // 'MyError'
    console.log(e.message); // 'custom message'
}

ES5 写法用原型链挂到 Error.prototype(仍有效;新代码优先用 class extends Error):

function MyError(message) {
    this.name = 'MyError';
    this.message = message || 'Default Message';
    this.stack = new Error().stack;
}
MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;

抛出和捕获异常

throw

throw 语句用来抛出一个异常。当前函数的执行将被停止(throw 之后的语句将不会执行),并且控制将被传递到调用堆栈中的第一个 catch 块。如果调用者函数中没有 catch块,程序将会终止。

try {
    throw new Error('This is a Error!');
} catch (e) {
    console.log(e.name);    // 'Error'
    console.log(e.message); // 'This is a Error!'
}

注意: throw 可以抛出任何类型的值。也就是说,除了 Error 类型,还可以抛出 JavaScript 中的任何值。

try...catch

try...catch 语句用于对指定的某个语句块内抛出的异常的响应。

try 语句包含一个 try 块,和至少一个 catch 或者 finally 块的。

  • try...catch
  • try...finally
  • try...catch...finally

catch 块包含 try 块中抛出异常时要执行的语句。也就是,如果 try 块中有任何一个语句(或者调用的函数)抛出异常,会立即转向 catch 块的语句;如果没有异常抛出,会跳过 catch 块。

finally 块在 try 块 和 catch 块之后执行。无论是否抛出异常 finally 块都会执行。此外,如果抛出异常,即使没有catch 块处理异常,finally 块的语句也会执行。

try {
    throw new Error('This is a Error!')
} catch (e) {
    console.log(e) // Error: This is a Error! at ...。
} finally {
    console.log('Finally!') // Finally!
}

如果 finally 块有 return 语句,那么该返回值将会成为整个 try-catch-finally 的返回值,无论 try 和 catch 块是否有 return 语句。

function funcTry() {
    try {       return 1 }
    catch (e) { return 2 }
    finally {   return 3 }
}
console.log('返回值:', funcTry()) // '返回值: 3'

try 语句可以嵌套一个或者多个的 try 语句。如果 try 语句 没有 catch 块,那么抛出的异常将会被包裹它的 try 语句的 catch 块捕获。

try {
    try {     throw new Error("Error inner!"); }
    finally { console.log("Finally inner!"); }
}
catch (e) { console.error(e); }
finally {   console.log("Finally outer!");}
// Finally inner!
// Error: Error inner! at xxx
// Finally outer!

JSON 对象

JSON(JavaScript Object Notation)是一种基于文本的标准格式,用来表示结构化数据,可序列化对象、数组、数值、字符串、布尔值和 null

网络上传输的是 JSON 文本(字符串)JSON.parse 之后才是 JavaScript 值。不要把「JSON 对象」和普通 JS 对象混为一谈。

注意: JSON 的语法来自 JavaScript 对象字面量,但 JSON 不是 JavaScript。

JSON 格式

JSON 是一种基于 JavaScript 对象语法的数据格式。

JSON 可以写成对象字面量,也可以写成字符串:运行时解读用对象(或解析后的值);通过网络传输必须用字符串。

另外,一个 JSON 对象可以储存在一个单独的文件中,该文件基本上就是一个文本文件,扩展名为 .json,对应的媒体类型(MIME type)为 application/json

JSON 格式注意事项

  • JSON 是一种纯数据格式,只包含属性,没有方法。
  • 属性名称和字符串必须放在双引号内,单引号无效。
  • 一个意外的逗号或分号就可能导致 JSON 文件出错。如,数组或对象最后一个成员后面的逗号。
  • 属性值是引用类型:只能是数组或对象,不能是函数、正则表达式对象、日期对象。
  • 属性值是基本类型:只能是字符串、数值(十进制,且不能是 NaN、Infinity、-Infinity)、布尔值和 null,不能是 undefined。
  • 属性值是数值:禁止出现前导零。
  • 属性值是小数:小数点后面至少跟着一位数字。

JSON 方法

JavaScript 提供一个全局的 JSON 对象来对 JSON 对象和 JSON 字符串进行转换。

JavaScript 内置的 JSON 对象只有两个方法:stringify()、parse()。除此之外,JSON 对象本身并没有其他作用,也不能被调用或者作为构造函数调用。

stringify()

用于将一个 JavaScript 对象或值转换为 JSON 字符串。

JSON.stringify(value[, replacer [, space]])

value 是一个将要被序列化成 JSON 字符串的 JSON 对象。 replacer 可以是一个函数或数组。如果是函数,则 JSON 对象的每个属性都会经过该函数的转换和处理;如果是数组,则只有在数组中的属性名才会被序列化;如果是 null 或者未提供,则对象所有的属性都会被序列化。

const json = { a: 1, b: 2 }
const jsonStr = JSON.stringify(json, function (key, value) {
    if (key === '') { return value }
    return value + 100
})
console.log(jsonStr) // {"a":101,"b":102}

replacer 是函数可以传入键(key)和值(value)两个参数。replacer 函数第一次调用时,key 是一个空字符串,value 是 stringify() 方法的第一个参数;第二次及以后的每次调用,都是对上一次调用的返回值的递归,即,如果上一次的返回值是可序列化的,则会继续调用 stringify() 方法。

const jsonStr = JSON.stringify(json, function (key, value) {
    if (key === '') {
        console.log(value) // {a: 1, b: 2}
        return { c: 'c', d: 'd' }
    }
    return value + 100
})
console.log(jsonStr) // {"c":"c100","d":"d100"}

space 是指定缩进用的空白字符串,用于美化输出。如果是数值,则代表有多少个(1~10,小于 1 意味着没有空格)空格;如果是字符串(长度超过 10,截取前 10),则该字符串将被作为空格;如果是 null 或者未提供,表示没有空格。

const jsonStr = JSON.stringify(json, null, 8)
// '{\n        "a": 1,\n        "b": 2\n}'

stringify() 转换规则:

  • 传参是函数、undefined 会返回 undefined。
  • 布尔值、数字、字符串的包装对象会自动转换成对应的原始值。
  • undefined、函数、Symbol 值:在非数组对象中将会被忽略;在数组中被转换成 null。
  • NaN、Infinity、null 会转换为 null。
  • 所有属性名是 Symbol 值的属性会被忽略。
  • 非数组对象的属性不能保证以特定的顺序序列化。
  • 如果属性值是对象,且该对象内有 toJSON() 方法,则该对象的序列化值为 toJSON() 方法的返回值。
  • 不能包含循环引用的对象。
  • Date 对象内置了 toJSON() 方法,Date 会被转成字符串,结果与 Date.prototype.toISOString() 相同。
  • 其他类型的对象仅会序列化可枚举的属性。
// 传参是函数、undefined 会返回 undefined
JSON.stringify(function () {}) // undefined
JSON.stringify(undefined)      // undefined

// 不能包含循环引用的对象
const obj = { a: 1 }
obj.b = obj
JSON.stringify(obj) // Uncaught TypeError: Converting circular structure to JSON

const json = {
  NaN: NaN,
  Infinity: Infinity,
  null: null,
  [Symbol('Symbol')]: 'Symbol',
  Date: new Date(),
  array: [undefined, function () { }, Symbol('Symbol')],
  obj: {
    undefined: undefined,
    fn: function () { },
    Symbol: Symbol('Symbol')
  },
  jsonObj: {
    toJSON: function () { return '自定义' }
  }
}
JSON.stringify(json) // {"NaN":null,"Infinity":null,"null":null,"Date":"2022-05-21T06:32:12.184Z","array":[null,null,null],"obj":{},"jsonObj":"自定义"}

parse()

用于将一个 JSON 字符串转换为 JavaScript 对象或值。

JSON.parse(text[, reviver])

text 是要被解析成 JavaScript 值的字符串。若传入的字符串不符合 JSON 规范,则会抛出 SyntaxError 异常。 reviver 是一个函数,用来在返回解析值之前,修改解析值,返回修改后的解析值。该函数接收键(key)和值(value)两个参数。

reviver 函数解析对象本身以及它所包含的所有属性,会按照一定的顺序(从最最里层的属性开始,一级级往外,最终到达顶层,也就是解析值本身)调用,在调用过程中,当前属性所属的对象会作为 this 值。如果返回 undefined,则当前属性会被忽略;如果返回其他值,则会成为当前属性新的值。

当遍历到最顶层的值时(即最后一次调用),传入函数的参数会是空字符串和最终返回的解析值(有可能已经被修改过了),当前的 this 值会是 {"": [最终返回的解析值]}

const jsonStr = '{"a": 1, "b": 1}'
const json = JSON.parse(jsonStr, function (key, value) {
    console.log(key, value)
    if (key === '') {
        return { c: 'c', d: 'd' }
    }
    return value
})

// a 1
// b 1
// {c: 'c', d: 'd'}

注意: JSON 文本里数值禁止前导零(01 非法)。JSON.parse('{"a":01}') 会抛 SyntaxErrorJSON.stringify 处理的是 JS 值,不会把数字写成带前导零的文本。

Math 对象

Math 是一个内置对象,拥有一些数学常数属性和数学函数方法,主要用于 Number 类型计算,且不支持 BigInt 类型。

与其他全局对象不同的是,Math 不是一个构造函数,它的所有属性与方法都是静态的。

Math 属性

  • E: 欧拉常数,也是自然对数的底数,约等于 2.718。
  • LN2: 2 的自然对数,约等于 0.693。
  • LN10: 10 的自然对数,约等于 2.303。
  • LOG2E: 以 2 为底的 E 的对数,约等于 1.443。
  • LOG10E: 以 10 为底的 E 的对数,约等于 0.434。
  • PI: 圆周率,一个圆的周长和直径之比,约等于 3.14159。
  • SQRT1_2: 二分之一的平方根,同时也是 2 的平方根的倒数,约等于 0.707。
  • SQRT2: 2 的平方根,约等于 1.414。

Math 的常量是使用 JavaScript 中浮点数的最大精度来定义的。

Math.E  // 2.718281828459045
Math.PI // 3.141592653589793

Math 方法

  • abs(x): 返回一个数的绝对值。
  • max([x[, y[, …]]]): 返回零到多个数值中最大值。
  • min([x[, y[, …]]]): 返回零到多个数值中最小值。
  • random(): 返回一个 0 到 1 之间的伪随机数。
  • round(x): 返回按「四舍五入到最近整数、.5 向正无穷方向取整」后的整数。例如 Math.round(0.5) 为 1,Math.round(-0.5) 为 0,负半值并不对称。
  • ceil(x): 返回大于一个数的最小整数,即一个数向上取整后的值。
  • floor(x): 返回小于一个数的最大整数,即一个数向下取整后的值。
  • sign(x): 返回一个数的符号,得知一个数是正数、负数还是 0。

  • trunc(x): 返回一个数的整数部分,直接去除其小数点及之后的部分。

  • pow(x, y): 返回一个数的 y 次幂。

  • sqrt(x): 返回一个数的平方根。

  • cbrt(x): 返回一个数的立方根。

  • hypot([x[, y[, …]]]): 返回其所有参数平方和的平方根。
  • log(x): 返回一个数的自然对数(㏒e,即 ㏑)。
  • log1p(x): 返回一个数加 1 的和的自然对数(㏒e,即 ㏑)。
  • log10(x): 返回一个数以 10 为底数的对数。
  • log2(x): 返回一个数以 2 为底数的对数。
  • exp(x): 返回欧拉常数的参数次方,E^x,其中 x 为参数,E 是欧拉常数(2.718...,自然对数的底数)。
  • expm1(x): 返回 exp(x) - 1 的值。

  • clz32(x): 返回一个 32 位整数的前导零的数量。

  • fround(x): 返回最接近一个数的单精度浮点型表示。
  • imul(x, y): 返回 32 位整数乘法的结果。

  • sin(x): 返回一个数的正弦值。

  • sinh(x): 返回一个数的双曲正弦值。

  • asin(x): 返回一个数的反正弦值。

  • asinh(x): 返回一个数的反双曲正弦值。

  • cos(x): 返回一个数的余弦值。

  • cosh(x): 返回一个数的双曲余弦值。

  • acos(x): 返回一个数的反余弦值。

  • acosh(x): 返回一个数的反双曲余弦值。
  • tan(x): 返回一个数的正切值。
  • tanh(x): 返回一个数的双曲正切值。
  • atan(x): 返回一个数的反正切值。
  • atanh(x): 返回一个数的反双曲正切值。
  • atan2(y, x): 返回 y/x 的反正切值。
  • toSource()(非标准,已过时): Firefox 曾返回字符串 "Math"。现行浏览器已移除,不要使用。

注意: 三角函数 sin()、cos()、tan()、asin()、acos()、atan() 和 atan2() 返回的值是弧度而非角度。若要转换,弧度除以 (Math.PI / 180) 即可转换为角度。同理,角度乘以这个数则能转换为弧度。

注意: 很多 Math 函数都有一个精度,而且这个精度在不同实现中也是不相同的。这意味着不同的浏览器会给出不同的结果,甚至,在不同的系统或架构下,相同的 JS 引擎也会给出不同的结果!

console 对象

Console 对象提供了浏览器控制台调试的接口。在不同浏览器上它的工作方式可能不一样,但通常都会提供一套共性的功能。

Console 对象可以从任何全局对象中访问到,如:浏览器作用域上的 Window、Web Worker 的 WorkerGlobalScope。

console 方法

  • log(): 打印内容的通用方法,Info 类型。

  • info(): 打印资讯类说明信息,Info 类型。

  • warn(): 打印一个警告信息,Warnings 类型。

  • error(): 打印一条错误信息,Errors 类型。

  • debug(): 打印一条调试信息,Verbose 类型。

  • trace(): 输出一个 stack trace。

    console.trace()
    // console.trace
    // (anonymous) @ [fileName]:[lineNo]
    
  • count(): 以参数为标识记录 count() 调用的次数。如果省略参数,默认为 default

  • countReset(): 重置指定标识的计数器值。如果省略参数,此函数会重置默认的计数器。

  • dir(): 在控制台中显示指定 JavaScript 对象的属性,并通过类似文件树样式的交互列表显示。

    console.dir(document.querySelector('body'))
    // aLink: ""
    // accessKey: ""
    // ...
    
  • dirxml(): 显示一个明确的XML/HTML元素的包括所有后代元素的交互树。

    console.dirxml(document.querySelector('body'))
    // <body>
    //   <div>...</div>
    //   <script>...</script>
    // </body>
    
  • table(): 将列表型的数据打印成表格。

    console.table(["apples", "oranges", "bananas"]);
    console.table(["John", "Smith"], ["Jane", "Doe"], ["Emily", "Jones"]);
    
    function Person(firstName, lastName) {
      this.firstName = firstName;
      this.lastName = lastName;
    }
    console.table([
        new Person("John", "Smith"),
        new Person("Jane", "Doe"),
        new Person("Emily", "Jones")
    ], ["firstName"]); // 过滤属性名为 firstName 的列。
    
  • assert(): 如果第一个参数 false,则将一个错误消息写入控制台;如果是 true,没有任何反应。

    console.assert(false, 'The word is %s', 'Hello!');
    // Assertion failed: The word is Hello!
    
    console.assert(true, 'The word is %s', 'Hello!'); // undefined
    
  • clear(): 清空控制台,并输出 Console was cleared

  • group(): 创建一个新的分组,后续所有打印内容将会以子层级的形式展示,直到调用 groupEnd() 之后,当前分组结束。

  • groupEnd(): 关闭当前分组,即当前最近的一个 group() 创建的分组。

  • groupCollapsed():与 group() 类似,不同的是,该方法打印出来的内容默认是折叠的。

  • profile()(非标准): 开始记录性能描述信息

  • profileEnd()(非标准):停止记录之前已经由 profile() 开始记录的性能描述信息。

  • time(): 启动一个计时器来跟踪某一个操作的占用时长。每一个计时器必须拥有唯一的名字,页面中最多能同时运行 10,000 个计时器。

  • timeLog(): 在控制台输出一个 time() 启动的计时器的值。

  • timeEnd(): 停止一个 time() 启动的计时器,并以毫秒打印其从开始到结束所用的时间。

  • timeStamp()(非标准): 添加一个标记到浏览器的 Timeline 或 Waterfall 工具。

字符串替换

console 的方法支持以下占位符,不同类型的数据必须使用对应的占位符:

  • %s: 字符串。
  • %d、%i: 整数。
  • %f: 浮点数,支持格式化。
  • %o、%O: JavaScript 对象。
  • %c: CSS 格式字符串,指定输入的样式。
console.log("String: %s", 'abcd')           // String: abcd
console.log("Number: %d %d %2d", 1, 1.0001) // Number: 1 1 %2d
console.log("Float: %f %f", 1, 1.0001)      // Float: 1 1.0001
console.log("Object: %o", { a: 1, b: 2 })   // Object: {a: 1, b: 2}
console.log("String: %c%s %c efg", 'color: red;', 'abcd', 'color: green')
// String: abcd  efg。输出内容会显示不同颜色

如果输出的内容与指定类型不符,则会强制转换为指定类型。

console.log("Number: %d", 'abcd')         // Number: NaN
console.log("String: %s", { a: 1, b: 2 }) // String: [object Object]

定义样式

可以使用 %c 占位符为打印内容定义样式。

占位符前的文本不受影响,占位符后的文本将会使用参数中声明的 CSS 样式。

console.log("This is a %ccolorful %cstring!", "color: red;", "color: green;");

%c 占位符可用的属性如下(不同浏览器可能存在差异):

background
border
border-radius
box-decoration-break
box-shadow
clear
float
color
cursor
display
font
line-height
margin
outline
padding
text-*
white-space
word-spacing
word-break
writing-mode

备注: 控制台信息的默认行为与行内元素相似,可以通过 display 属性修改盒模型。

debugger 语句

debugger 语句调用任何可用的调试功能。当被调用时,执行暂停在 debugger 语句的位置,如同在脚本源代码中的断点一样。

如果没有调试功能可用,则此语句不起作用。

参考资料

MDN - Error

MDN - 使用JSON

MDN - JSON

MDN - Math

MDN - Console

© lizhao all right reserved,powered by Gitbook文件修订时间: 2026-08-31 20:47:09

results matching ""

    No results matching ""