本文涉及类型检查,错误对象以及attempt函数本身
类型检查
getTag
const toString = Object.prototype.toString
/**
* Gets the `toStringTag` of `value`.
*
* @private
* @param {*} value The value to query.
* @returns {string} Returns the `toStringTag`.
*/
function getTag(value) {
if (value == null) {
// 兼容javascript低版本,特殊处理null和undefined
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return toString.call(value)
}
isObjectLike
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
* 校验一个对象是否是一个object-like对象。一个object-like不是null并且typeof返回值为object
*
* @since 4.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is object-like, else `false`.
* @example
*
* isObjectLike({})
* // => true
*
* isObjectLike([1, 2, 3])
* // => true
*
* isObjectLike(Function)
* // => false
*
* isObjectLike(null)
* // => false
*/
function isObjectLike(value) {
return typeof value === 'object' && value !== null
}
isPlainObject
依赖于getTag函数以及isObjectLike函数
是否是通过Object构造函数直接创建的对象,创建方式
{}对象字面量Object.create({})方法Object({})方法
/**
* Checks if `value` is a plain object, that is, an object created by the
* `Object` constructor or one with a `[[Prototype]]` of `null`.
* 直接由`Object`构造函数创建的对象 或者 对象的prototype 为 null 的对象
*
* @since 0.8.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is a plain object, else `false`.
* @example
*
* function Foo() {
* this.a = 1
* }
*
* isPlainObject(new Foo)
* // => false
*
* isPlainObject([1, 2, 3])
* // => false
*
* isPlainObject({ 'x': 0, 'y': 0 })
* // => true
*
* isPlainObject(Object.create(null))
* // => true
*/
function isPlainObject(value) {
if (!isObjectLike(value) || getTag(value) != '[object Object]') {
return false
}
// 通过Object.create(null)创建的对象
// console.log( Object.getPrototypeOf(Object.create(null)))
if (Object.getPrototypeOf(value) === null) {
return true
}
let proto = value
// 按对象原型链向上查找
while (Object.getPrototypeOf(proto) !== null) {
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(value) === proto
}
isError
原生Error对象,主要包含name,message,toString这几个属性。详见mdn
/**
* Checks if `value` is an `Error`, `EvalError`, `RangeError`, `ReferenceError`,
* `SyntaxError`, `TypeError`, or `URIError` object.
*
* @since 3.0.0
* @category Lang
* @param {*} value The value to check.
* @returns {boolean} Returns `true` if `value` is an error object, else `false`.
* @example
*
* isError(new Error)
* // => true
*
* isError(Error)
* // => false
*/
function isError(value) {
// 不是一个"类"对象
if (!isObjectLike(value)) {
return false
}
// 获取对象错误类型
const tag = getTag(value)
return tag == '[object Error]' || tag == '[object DOMException]' ||
// error message 属性为 string 类型 并且 name 属性为 string 类型 并且不是通过直接调用Object构造函数直接创建的对象
(typeof value.message === 'string' && typeof value.name === 'string' && !isPlainObject(value))
}
attempt
尝试执行传入的函数或捕获相应的错误对象并返回。函数执行的参数由传入attemp函数的参数决定。
/**
* Attempts to invoke `func`, returning either the result or the caught error
* object. Any additional arguments are provided to `func` when it's invoked.
* 尝试执行传入的函数,返回执行函数的值或捕获错误对象。任意传递给attempt函数的额外参数都会传递给func
*
* @since 3.0.0
* @category Util
* @param {Function} func The function to attempt.
* @param {...*} [args] The arguments to invoke `func` with.
* @returns {*} Returns the `func` result or error object.
* @example
*
* // Avoid throwing errors for invalid selectors.
* const elements = attempt(selector =>
* document.querySelectorAll(selector), '>_>')
*
* if (isError(elements)) {
* elements = []
* }
*/
function attempt(func, ...args) {
try {
return func(...args)
} catch (e) {
return isError(e) ? e : new Error(e)
}
}