1. 背景
上一期了解了JavaScript 基础类型的判断 ,但唯独少了 Array。这期便来讲讲 xe-utils 源码中对是否 Array
的判断。
如果使用 typeof
来判断 Array
的话,返回的只会是一个 object
,如下
const arr = []
console.log(typeof arr) // object
那源码中是如何判断 Array 的呢?
2. 源码解析
要判断是否为 Array
类型,不能使用 typeof
;也许你想到了,用 Array.isArray
来判断不失为一个好方法,但查看源码后发现其写法如下
2.1 isArray.js
源码中先尝试用 Array.isArray
进行判断;
若该方法不存在,则使用 helperCreateInInObjectString
构造出来的方法进行判断
var helperCreateInInObjectString = require('./helperCreateInInObjectString')
var isArray = Array.isArray || helperCreateInInObjectString('Array')
module.exports = isArray
源码为何要这么实现?有两个细节
- 【兼容性】
Array.isArray
是 ES6 中才有的方法,因此只用Array.isArray
的话,兼容性不足 - 【扩展性】尽管
Array.isArray
可以判断出 Array,但在 JavaScript 中,不止Array
用typeof
判断不出来,诸如此类的还有如下:
typeof new Date(); // object
typeof new Error(); // object
typeof new RegExp(); // object
为了同时具备兼容性和扩展性,helperCreateInInObjectString
中实现了什么方法呢?
2.2 helperCreateInInObjectString.js
// helperCreateInInObjectString.js
var objectToString = require('./staticObjectToString')
function helperCreateInInObjectString (type) {
return function (obj) {
return '[object ' + type + ']' === objectToString.call(obj)
}
}
module.exports = helperCreateInInObjectString
上述函数的功能,在于将要判断的值,转化为形如:[object Object]
的字符串形式再进行判断,部分示例如下:
objectToString.call([]) // [object Array]
objectToString.call("") // [object String]
objectToString.call(/\d/) // [object RegExp]
该方法可以兼容低版本浏览器,且能判断更多类型,从设计模式的角度上看,使用了工厂模式封装了一个公共的判断方法。既实现了向下兼容,也具备可扩展性。
而将值转换为形如 [object Object]
的核心代码 objectToString
,内部是如何实现?
2.3 staticObjectToString.js
var objectToString = Object.prototype.toString
module.exports = objectToString
可以看到,运用了 toString
方法来实现,故在许多工具类中,可以经常见到用该方法 Object.prototype.toString.call(obj)
来获取形如 [object Object]
的字符串。例如 underscore.js
工具类,其实现与本文所提有异曲同工之妙:
// underscore.js
function tagTester(name) {
var tag = '[object ' + name + ']';
return function(obj) {
return toString.call(obj) === tag;
};
}
var isString = tagTester('String');
var isNumber = tagTester('Number');
var isDate = tagTester('Date');
var isRegExp = tagTester('RegExp');
var isError = tagTester('Error');
var isSymbol = tagTester('Symbol');
var isArrayBuffer = tagTester('ArrayBuffer');
var isFunction = tagTester('Function');