基础篇 07 Error、JSON、Math、Console对象

Error对象

通过 Error 的构造器可以创建一个错误对象。当代码运行时的发生错误,会创建新的 Error 对象,并将其抛出。Error 对象也可用于用户自定义的异常的基础对象。

new Error([message[, fileName[,lineNumber]]])

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

fileName(非标准)是被创建的 Error 对象的文件名,默认是调用 Error 构造器代码所在的文件的名字

lineNumber(非标准)是被创建的 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 函数没有被正确执行。

  • InternalError: JavaScript 引擎内部错误的异常抛出的实例。 如:递归太多。

  • RangeError: 数值变量或参数超出其有效范围。如:数组长度为负数、Number 对象的方法参数超出范围、函数堆栈超过最大值。

  • ReferenceError: 引用一个不存在的变量时发生的错误。

  • SyntaxError: 解析代码的过程中发生的语法错误。

  • TypeError: 变量或参数不属于有效类型。

  • URIError: URI 相关函数的参数不正确时抛出的错误。主要涉及:encodeURI()、decodeURI()、encodeURIComponent()、decodeURIComponent()、escape()和unescape() 这六个函数。

自定义异常类型

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;

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

抛出和捕获异常

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)是一种基于文本的标准格式,用于表示基于 JavaScript 对象语法的结构化数据,用来序列化对象、数组、数值、字符串、布尔值和 null 。

注意: JSON 是基于 JavaScript 语法,但 JSON 不是 JavaScript。

JSON格式

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

JSON 可以作为一个对象或者字符串存在:作为对象时,用于解读 JSON 中的数据;作为字符串时,用于通过网络传输 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.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 的属性值是数值,且带有前导零,JSON.stringify() 方法可能忽略前导零或者当作八进制解析(不同浏览器实现可能不一样),JSON.parse() 方法则会抛出 SyntaxError 错误。

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): 返回四舍五入后的整数。

  • 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(): 返回字符串 "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

最后更新于