关于JS类型判断的思考
初衷
写这篇文章的初衷是来源于 JS基础问题-类型判断 [1] ,仅当作巩固下知识。
我们常说学习一个知识点要学会延伸思考,点画线,线绘面,形成自己的知识体系。
一个小小的类型判断其实也可以拓展出很多知识点。
What: 什么是类型?
计算机程序的运行需要对值进行操作,而在编程语言中,能够表示并操作的值的类型称为数据类型。
编程语言最基本的特征就是支持多种数据类型。
Who:JS有哪几类数据类型,以及分别是什么?
JS有两类数据类型:原始类型(primitive type)和对象类型(object type)。
原始类型
• number • string • boolean • undefined • null • symbol • Bigint [2]
指的注意的是null确实属于基本类型,因为有时它容易被误认为是对象类型。
typeof null === 'object' // 这应该算语言的一个bug
对 typeof null 感兴趣的可以看这个讨论 [3] 。
对象类型
• object
实际上JS还有很多特殊的对象子类型,我们可以称之为复杂基本类型。
比如说:
• String • Number • Boolean • Function • Array • Date • Regexp • Error • Object • Buffer • Map • Set • WeakSet • WeakMap
这里又会有一个思考:基本数据类型与引用数据类型的区别,常见于函数的入参。
基本数据类型它是按值访问。
const a = 10;
let b = a;
b = 20;
引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址(“指针”)。通过这个引用地址可以快速查找到保存中堆内存中的对象。
const obj1 = new Object();
const obj2 = obj1;
obj2.name = "我有名字了";
Why:为什么我们需要自己实现JS类型判断?
因为JS自带的类型判断方法不能满足我们的需求。
JS自带的类型判断方法
• typeof
console.log(typeof '11') // string
console.log(typeof 11) // number
console.log(typeof true) // boolean
console.log(typeof undefined) // undefined
console.log(typeof null) // object, 算语言的bug,实际上该方式并不能判断出null
console.log(typeof Symbol('test')) // symbol
console.log(typeof /.?/gi) // object
console.log(typeof []) // object
console.log(typeof new Date()) // object
你会发现typeof只能判断基本数据类型(null还是一个特例,需要特殊处理),不适用于判断对象类型,因为它无法判断出具体的子类型。
下面几个简单题目测试下是否掌握了typeof用法。
var y = 1, x = y = typeof x;
console.log(x) // undefined
var foo = {
bar: function() { return this.baz; },
baz: 1
};
(function(){
return typeof arguments[0]();//"undefined"
})(foo.bar);
• instanceof
instanceof 主要的作用就是判断一个实例是否是其父类型或者祖先类型的实例。它是基于原型链的查找。
let person = function () {
}
let nicole = new person()
nicole instanceof person // true
我们看下面这个demo你就知道为什么有些场景下不能用instanceof来判断数据类型了。
const arr = []
const obj = {}
const func = function() {}
console.log(arr instanceof Array) // true
console.log(arr instanceof Object) // true
console.log(obj instanceof Object) // true
console.log(func instanceof Object) // true
How:如何实现JS类型判断?
下面我们看看lodash是如何进行JS类型判断的。
• _.isObjectLike(value) 类对象
/**
* Checks if `value` is object-like. A value is object-like if it's not `null`
* and has a `typeof` result of "object".
*
* isObjectLike({})
* // => true
*
* isObjectLike([1, 2, 3])
* // => true
*
* isObjectLike(Function)
* // => false
*
* isObjectLike(null)
* // => false
*/
function isObjectLike(value) {
return typeof value === 'object' && value !== null
}
export default isObjectLike
• _.isArguments(value) 类 arguments 对象
const toString = Object.prototype.toString
// Gets the `toStringTag` of `value`.
// 这个方法很重要
function getTag(value) {
if (value == null) {
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return toString.call(value)
}
function isArguments(value) {
return isObjectLike(value) && getTag(value) == '[object Arguments]'
}
• _.isArrayLike(value)
// 检查 value 是否为有效的类数组长度。
function isLength(value) {
return typeof value === 'number' &&
value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER
}
function isArrayLike(value) {
return value != null && typeof value !== 'function' && isLength(value.length)
}
• _isBoolean()
// isBoolean(null) false
function isBoolean(value) {
return value === true || value === false ||
(isObjectLike(value) && getTag(value) == '[object Boolean]')
}
这里就不详细列举,感兴趣强烈推荐阅读 lodash源码 [4]
关于类型还涉及的知识点有
• Primitive Types & Reference Types in JavaScript —— Bran van [5] • JS值引用与值复制 [6] • 动态类型语言与鸭子类型 [7] • 你不知道的javascript中卷-强制类型转换 [8] • JS类型的隐式转换 [9] • JS中的相等性判断 [10]
References
[1]
JS基础问题-类型判断: https://elemefe.github.io/node-interview/#/sections/zh-cn/common?id=%e7%b1%bb%e5%9e%8b%e5%88%a4%e6%96%ad
[2]
Bigint: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/BigInt
[3]
typeof null 感兴趣的可以看这个讨论: https://www.zhihu.com/question/66941121/answer/247939890
[4]
lodash源码: https://github.com/lodash/lodash
[5]
Primitive Types & Reference Types in JavaScript —— Bran van: https://link.zhihu.com/?target=https%3A//docstore.mik.ua/orelly/webprog/jscript/ch04_04.htm
[6]
JS值引用与值复制: https://link.zhihu.com/?target=https%3A//segmentfault.com/a/1190000015411195
[7]
动态类型语言与鸭子类型: https://link.zhihu.com/?target=http%3A//book.51cto.com/art/201505/475153.htm
[8]
你不知道的javascript中卷-强制类型转换: https://link.zhihu.com/?target=https%3A//www.jianshu.com/p/777a89b4ed9a
[9]
JS类型的隐式转换: https://link.zhihu.com/?target=https%3A//www.imooc.com/video/5675
[10]
JS中的相等性判断: https://link.zhihu.com/?target=https%3A//developer.mozilla.org/zh-CN/docs/Web/JavaScript/Equality_comparisons_and_sameness