# createError 函数分析

经过前面的章节学习,相信大家在很多地方都会看见通过 createError 这个函数创建一个错误对象。那么本章节,我们就来讲解 createError 的实现

# 源码分析

我们先来看看源码,源码在/lib/core/createError.js文件

var enhanceError = require("./enhanceError");

/**
 * 给error对象添加一些属性,然后返回
 *
 * @param {string} message 错误消息
 * @param {Object} config 配置项
 * @param {string} [code] 错误码
 * @param {Object} [request] 请求实例
 * @param {Object} [response] 响应数据对象
 * @returns {Error} 返回一个error对象
 */
module.exports = function createError(
  message,
  config,
  code,
  request,
  response
) {
  var error = new Error(message);
  return enhanceError(error, config, code, request, response);
};

enhanceError函数源码在/lib/core/enhanceError.js文件

/**
 * 给error对象添加额外的属性.
 *
 * @param {Error} error error对象
 * @param {Object} config 请求配置项
 * @param {string} [code] 错误码
 * @param {Object} [request] 请求对象
 * @param {Object} [response] 响应对象
 * @returns {Error} The error.
 */
module.exports = function enhanceError(error, config, code, request, response) {
  // 添加`config`请求配置项属性
  error.config = config;
  if (code) {
    // 添加错误码
    error.code = code;
  }
  // 添加请求实例
  error.request = request;
  // 添加响应数据对象
  error.response = response;
  // 标识这是一个经过axios封装过的错误对象
  error.isAxiosError = true;
  // JSON.stringify函数将对象转为字符串就是调用对象上的`toJSON`函数获取需要转化为字符串的key-value字段
  // 改写`error`对象身上的`toJSON`函数
  error.toJSON = function toJSON() {
    return {
      // Standard
      message: this.message,
      name: this.name,
      // Microsoft
      description: this.description,
      number: this.number,
      // Mozilla
      fileName: this.fileName,
      lineNumber: this.lineNumber,
      columnNumber: this.columnNumber,
      stack: this.stack,
      // Axios
      config: this.config,
      code: this.code,
    };
  };
  return error;
};

# 函数功能

通过上面的源码分析,我们可以看见createError函数内部创建了一个Error实例,然后调用了enhanceError函数,并把Error实例,config配置项等信息传给enhanceError函数。最终返回enhanceError函数的返回结果。

通过对enhanceError函数的分析,我们也不难发现,enhanceError函数实际上就是给Error对象实例添加一些额外属性,比如configrequest等属性,并且改写Error实例的toJSON函数

# 扩展

  • toJSON

enhanceError函数中,我们发现Error实例的toJSON函数被改写了,那么,toJSON函数的作用是什么呢?

其实,在我们调用JSON.stringify的时候,实际上就是调用了toJSON函数来获取该对象上面的属性。下面以几个简单的代码示例说明一下,这样子会更加直观

示例代码一:

const obj = {
  age: 1,
  toJSON() {
    return {
      name: "张三",
    };
  },
};
console.log(JSON.stringify(obj)); // ==>  {"name":"张三"}

实例代码二:

var obj = {
  age: 1,
  toJSON() {
    return "bar";
  },
};
console.log(JSON.stringify(obj)); // ==>  "bar"
  • valueOf 和 toString

valueOftoString 函数会在对象进行运算的时候执行,而且valueOf优先级比toString

当对象参与运算时,

如果valueOf能返回原始类型的值,会调用 valueOf方法,不调用toString方法,用valueOf的返回值参与运算

如果valueOf不能返回上述三类(字符串,数字,布尔)原始值的话,valueOftoString 都会调用。此时会看toString 的返回值。如果toString能返回三类(字符串,数字,布尔)原始值,会利用toString的返回值。

如果toStringvalueOf都不能返回上述三类(字符串,数字,布尔)原始类型的话,toStringvalueOf 都会调用,但是对应的返回值不用调用。同时会报错Cannot convert object to primitive value

下面以几个简单的代码示例说明一下,这样子会更加直观

示例代码一:

var obj = {
  age: 1,
  valueOf() {
    return "1";
  },
};
console.log(obj == 1); // ==> true

示例代码二:

var obj = {
  age: 1,
  toString() {
    return "2";
  },
};
console.log(obj == 2); // ==> true

示例代码三:

var obj = {
  age: 1,
  valueOf() {
    return {};
  },
  toString() {
    return "1";
  },
};
console.log(obj == 1); // ==> true

# 总结

通过本章的学习,相信你对createError函数的功能作用是什么应该有了一定的了解了。并且我们通过扩展,讲解了对象上面toJSONvalueOftoString函数的作用

在下一个章节,我们将会讲解 axios 的请求配置项有什么