GitHub地址:JavaScript 类型判断知多少
博客地址:JavaScript 类型判断知多少
水平有限,欢迎批评指正
getType
Returns the native type of a value.
Returns lowercased constructor name of value, “undefined” or “null” if value is undefined or null.
const getType = v => v === undefined ? 'undefined' : v === null ? 'null' : v.constructor.name.toLowerCase();
返回值的元类型。
返回值的 constructor
名的小写字母。undefined
或者 null
将会返回 undefined
或 null
。
➜ code git:(master) cat getType.js
const getType = v => v === undefined ? 'undefined' : v === 'null' ? 'null' : v.constructor.name.toLowerCase();
console.log(getType(new Set([1, 2, 3])));
console.log(getType(new Array(1, 2, 3)));
console.log(getType(Object.create({a: 1})));
➜ code git:(master) node getType.js
set
array
object
字面意思很好理解,不多说。
is
Checks if the provided value is of the specified type.
Ensure the value is not
undefined
ornull
usingArray.includes()
, and compare theconstructor
property on the value withtype
to check if the provided value is of the specifiedtype
.const is = (type, val) => ![, null].includes(val) && val.constructor === type;
检测提供的 val
是否属于指定的类型 type
。
运用 Array.includes()
确保 undefined
和 null
被排除在外,并且比较 val
的 constructor
属性和指定的类型 type
是否相等。
➜ code git:(master) ✗ cat is.js
const is = (type, val) => ![, null].includes(val) && val.constructor === type;
console.log(is(Array, [1]));
console.log(is(ArrayBuffer, new ArrayBuffer()));
console.log(is(Map, new Map()));
console.log(is(RegExp, /./g));
console.log(is(Set, new Set()));
console.log(is(WeakMap, new WeakMap()));
console.log(is(WeakSet, new WeakSet()));
console.log(is(String, ''));
console.log(is(String, new String('')));
console.log(is(Number, 1));
console.log(is(Number, new Number(1)));
console.log(is(Boolean, true));
console.log(is(Boolean, new Boolean(true)));
➜ code git:(master) ✗ node is.js
true
true
true
true
true
true
true
true
true
true
true
true
true
MDN
的 constructor ,你值得拥有。
isArrayLike
Checks if the provided argument is array-like (i.e. is iterable).
Use the spread operator (
...
) to check if the provided argument is iterable inside atry... catch
block and the comma operator (,
) to return the appropriate value.const isArrayLike = val => { try { return [...val], true; } catch (e) { return false; } };
检测变量是否是类数组
(比如是可迭代对象)。
结合 try... catch
使用 …
扩展运算表达式对提供的变量进行是否可迭代的检测,同时使用 ,
运算表达式返回适当的结果。
➜ code git:(master) ✗ cat isArrayLike.js
const isArrayLike = val => {
try {
return [...val], true;
} catch (e) {
return false;
}
};
console.log(isArrayLike('abc'));
console.log(isArrayLike(null));
➜ code git:(master) ✗ node isArrayLike.js
true
false
在这里类数组判断的依据是变量可迭代,所以对应的检测方法就是可以用扩展运算表达式 …
进行展开,如果能正确展开,返回 true
,否则返回 false
。
return [...val], true
,这里如果能展开,会能执行到 ,
表达式,返回 true
,否则将进入 catch
流程而返回 false
。
lodash
对于 isArrayLike
(类数组)的判断依据是变量不是 undefined
或者 null
,也不是 function
,同时含有 length
属性且该属性值是一个整数并且大于等于 0
且小于等于 Number.MAX_SAFE_INTEGER
(9007199254740991)。
const MAX_SAFE_INTEGER = 9007199254740991
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)
}
代码和逻辑一一对应,不细讲。不过换我写的话,我会把 ==
都写成 ===
。即使 value != null
写成 value !== null && value !== undefined
会变得很长。
isBoolean
Checks if the given argument is a native boolean element.
Use
typeof
to check if a value is classified as a boolean primitive.const isBoolean = val => typeof val === 'boolean';
检测提供的变量是否是布尔类型。
用 typeof
来检测 val
是否应该归为布尔原型。
➜ code git:(master) ✗ cat isBoolean.js
const isBoolean = val => typeof val === 'boolean';
console.log(isBoolean(null));
console.log(isBoolean(false));
➜ code git:(master) ✗ node isBoolean.js
false
true
布尔型直接用 typeof
就能判断。
isEmpty
Returns true if the a value is an empty object, collection, map or set, has no enumerable properties or is any type that is not considered a collection.
Check if the provided value is
null
or if itslength
is equal to0
.const isEmpty = val => val == null || !(Object.keys(val) || val).length;
如果 value
是一个空的 object
、collection
、map
或者 set
,或者没有任何可枚举的属性以及任何没有被当做 collection
的类型都返回 true
。
检测提供的变量是否为 null
或者变量的 length
属性是否等于0。
➜ code git:(master) ✗ cat isEmpty.js
const isEmpty = val => val == null || !(Object.keys(val) || val).length;
console.log(isEmpty(new Map()));
console.log(isEmpty(new Set()));
console.log(isEmpty([]));
console.log(isEmpty({}));
console.log(isEmpty(''));
console.log(isEmpty([1, 2]));
console.log(isEmpty({ a: 1, b: 2 }));
console.log(isEmpty('text'));
console.log(isEmpty(123));
console.log(isEmpty(true));
➜ code git:(master) ✗ node isEmpty.js
true
true
true
true
true
false
false
false
true
true
这里注意的是 val == null
用的是 ==
而不是 ===
,也就是说 undefined
也会返回 true
。
isFunction
Checks if the given argument is a function.
Use
typeof
to check if a value is classified as a function primitive.const isFunction = val => typeof val === 'function';
检测提供的变量的类型是否是 function
。
使用 typeof
进行判断给定的变量是否是 function
原型。
➜ code git:(master) ✗ cat isFunction.js
const isFunction = val => typeof val === 'function';
console.log(isFunction('x'));
console.log(isFunction(x => x));
➜ code git:(master) ✗ node isFunction.js
false
true
类型为 function
的判断比较简单,只需要用 typeof
就可以区分。
isNil
Returns
true
if the specified value isnull
orundefined
,false
otherwise.Use the strict equality operator to check if the value and of
val
are equal tonull
orundefined
.const isNil = val => val === undefined || val === null;
指定的变量是 null
或者 undefined
,返回 true
,否则返回 false
。
使用严格相等运算符去对变量进行是否等于 null
或者 undefined
的检测。
➜ code git:(master) ✗ cat isNil.js
const isNil = val => val === undefined || val === null;
console.log(isNil(null));
console.log(isNil(undefined));
➜ code git:(master) ✗ node isNil.js
true
true
这还真没啥好说的了,我觉得名字起得非常好,go
也用 nil
。
isNull
Returns
true
if the specified value isnull
,false
otherwise.Use the strict equality operator to check if the value and of
val
are equal tonull
.const isNull = val => val === null;
如果变量是 null
,返回 true
,否则返回 false
。
使用严格相等运算符判断变量是否为 null
。
➜ code git:(master) ✗ cat isNull.js
const isNull = val => val === null;
console.log(isNull(null));
➜ code git:(master) ✗ node isNull.js
true
isUndefined
Returns
true
if the specified value isundefined
,false
otherwise.Use the strict equality operator to check if the value and of
val
are equal toundefined
.const isUndefined = val => val === undefined;
如果变量是 undefined
,返回 true
,否则返回 false
。
使用严格相等运算符判断变量是否为 undefined
。
➜ code git:(master) ✗ cat isUndefined.js
const isUndefined = val => val === undefined;
console.log(isUndefined(undefined));
➜ code git:(master) ✗ node isUndefined.js
true
isNumber
Checks if the given argument is a number.
Use
typeof
to check if a value is classified as a number primitive.const isNumber = val => typeof val === 'number';
检测提供的变量是否为 number
型。
使用 typeof
检测给定变量是否是 number
原型。
➜ code git:(master) ✗ cat isNumber.js
const isNumber = val => typeof val === 'number';
console.log(isNumber('1'));
console.log(isNumber(1));
console.log(isNumber(NaN));
➜ code git:(master) ✗ node isNumber.js
false
true
true
这里注意的是 NaN
也是一个 number
类型。
isObject
Returns a boolean determining if the passed value is an object or not.
Uses the
Object
constructor to create an object wrapper for the given value. If the value isnull
orundefined
, create and return an empty object. Οtherwise, return an object of a type that corresponds to the given value.const isObject = obj => obj === Object(obj);
检测给定的变量是否为 object
类型。
使用 Object
的 constructor
对给定的变量构造一个对象。如果变量是 null
或者 undefined
,将会生成一个空对象。否则生成一个类型和变量本身相等的对象。
➜ code git:(master) ✗ cat isObject.js
const isObject = obj => obj === Object(obj);
console.log(isObject([1, 2, 3, 4]));
console.log(isObject([]));
console.log(isObject(['Hello!']));
console.log(isObject({ a: 1 }));
console.log(isObject({}));
console.log(isObject(x => x));
console.log(isObject(true));
➜ code git:(master) ✗ node isObject.js
true
true
true
true
true
true
false
数组、对象、方法都会返回 true
。这里跟 lodash
的 isObject
有点不太一样:
function isObject(value) {
const type = typeof value
return value != null && (type == 'object' || type == 'function')
}
对于 null
来说 typeof value === 'object'
,所以这是必须要排除掉的, 但是直接用 value != null
进行判断比 typeof
运行的效率高。
对于数组和对象来说,typeof
都会返回 object
。所以 type == 'object'
就能包含两者。
另外 typeof
值为 function
也满足,所以加上一个 ||
即可。
其实本质上用构造函数和 lodash
的判断方法一样,但是 lodash
没有涉及原型链的操作。所以效率高,虽然写法上比较费事。
isObjectLike
Checks if a value is object-like.
Check if the provided value is not
null
and itstypeof
is equal to'object'
.const isObjectLike = val => val !== null && typeof val === 'object';
检测一个变量是否是类对象。
只需要判断给定变量不是 null
且 typeof
结果与 object
相等即可。
➜ code git:(master) ✗ cat isObjectLike.js
const isObjectLike = val => val !== null && typeof val === 'object';
console.log(isObjectLike({}));
console.log(isObjectLike([1, 2, 3]));
console.log(isObjectLike(x => x));
console.log(isObjectLike(null));
➜ code git:(master) ✗ node isObjectLike.js
true
true
false
false
这里判断方法和 lodash
的 isObjectLike
一样。
isPlainObject
Checks if the provided value is an object created by the Object constructor.
Check if the provided value is truthy, use
typeof
to check if it is an object andObject.constructor
to make sure the constructor is equal toObject
.const isPlainObject = val => !!val && typeof val === 'object' && val.constructor === Object;
检测提供的变量是否是一个由对象的 constructor
创建的对象。
先判断变量的布尔运算是否为 true
,然后使用 typeof
判断变量是否为 object
,最后判断变量的 constructor
是否是 object
。这三个步骤的运算都为 true
才返回 true
。
➜ code git:(master) ✗ cat isPlainObject.js
const isPlainObject = val => !!val && typeof val === 'object' && val.constructor === Object;
console.log(isPlainObject({ a: 1 }));
console.log(isPlainObject(new Map()));
console.log(isPlainObject(Object.create(null)));
➜ code git:(master) ✗ node isPlainObject.js
true
false
false
代码正如注解一样一一对应,但意外的是它和 lodash
的 isPlainObject
是不一样的,唯一差别是 lodash
把 Object.create(null)
创建的对象也归为 plainObject
。但对应上各自的解释都是没错的。
lodash
的 isPlainObject
代码实现如下:
const objectProto = Object.prototype
const hasOwnProperty = objectProto.hasOwnProperty
const toString = objectProto.toString
const symToStringTag = typeof Symbol != 'undefined' ? Symbol.toStringTag : undefined
// baseGetTag
function baseGetTag(value) {
if (value == null) {
// undefined 和 null 直接用这种判断方式比较toString调用要快
return value === undefined ? '[object Undefined]' : '[object Null]'
}
// 排除 Symbol 时直接使用 toString 调用即可
if (!(symToStringTag && symToStringTag in Object(value))) {
return toString.call(value)
}
const isOwn = hasOwnProperty.call(value, symToStringTag)
const tag = value[symToStringTag]
let unmasked = false
try {
// 我猜这里是尝试把它的自有属性赋值为 undefined 是为了不干扰下面 toString 的调用
value[symToStringTag] = undefined
unmasked = true
} catch (e) {}
const result = toString.call(value)
// 如果try成功,需要还原
if (unmasked) {
if (isOwn) {
// 如果是自有属性,需要重新把值给回去
value[symToStringTag] = tag
} else {
// 如果不是自有属性,需要删除掉
delete value[symToStringTag]
}
}
return result
}
// isObjectLike
function isObjectLike(value) {
return typeof value == 'object' && value !== null
}
// isPlainObject
function isPlainObject(value) {
if (!isObjectLike(value) || baseGetTag(value) != '[object Object]') {
return false
}
if (Object.getPrototypeOf(value) === null) {
// 这里的 value 就是通过 Object.create(null) 来创建的
return true
}
let proto = value
while (Object.getPrototypeOf(proto) !== null) {
// 我猜是递归获取继承的 prototype
proto = Object.getPrototypeOf(proto)
}
return Object.getPrototypeOf(value) === proto
}
lodash
的代码我认为应该加注释的都加上了,不清楚的可以 MDN
自查:
isPrimitive
Returns a boolean determining if the passed value is primitive or not.
Use
Array.includes()
on an array of type strings which are not primitive, supplying the type usingtypeof
. Sincetypeof null
evaluates to'object'
, it needs to be directly compared.const isPrimitive = val => !['object', 'function'].includes(typeof val) || val === null;
检测变量是否是基本数据类型。
使用 Array.includes()
结合 typeof
把不是基本数据类型的排除掉。由于 typeof null
返回的是 object
,需要直接对它进行单独判断。
MDN
上关于 primitive
的解释如下:
A primitive (primitive value, primitive data type) is data that is not an object and has no methods. In JavaScript, there are 6 primitive data types: string, number, boolean, null, undefined, symbol (new in ECMAScript 2015).
primitive
(primitive 数值, primitive 数据类型) 是指不是一个 object
并且不包含方法的数据。在 JavaScript
中,属于 primitive
的是 string
、number
、boolean
、null
、undefined
和 symbol
(ECMAScript2015新增)。
➜ code git:(master) ✗ cat isPrimitive.js
const isPrimitive = val => !['object', 'function'].includes(typeof val) || val === null;
console.log(isPrimitive(null));
console.log(isPrimitive(50));
console.log(isPrimitive('Hello!'));
console.log(isPrimitive(false));
console.log(isPrimitive(Symbol()));
console.log(isPrimitive([]));
➜ code git:(master) ✗ node isPrimitive.js
true
true
true
true
true
false
!['object', 'function'].includes(typeof val)
这里就是把 typeof
运算结果为 object
或者 function
都排除掉,由于 null
的 typeof
是 object
,而 includes
会把它也排除了,需要用 ||
把它加回来。
如果你还有印象的话, isObject
正好是 isPrimitive
的对立面,所以其实我觉得 !isObject
也行。
lodash
暂时没有提供 isPrimitive
的计划,但在 issues
1406
中提到了可以用 !_.isObject(value)
或者 _.negate(_.isObject)
代替。
isPromiseLike
Returns
true
if an object looks like aPromise
,false
otherwise.Check if the object is not
null
, itstypeof
matches eitherobject
orfunction
and if it has a.then
property, which is also afunction
.const isPromiseLike = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
如果一个对象看起来像 Promise
,返回 true
,否则返回 false
。
首先该对象不能为 null
,其次它的 typeof
是 object
或者 function
之一,最后它有一个 .then
属性且该属性是一个 function
。
➜ code git:(master) ✗ cat isPromiseLike.js
const isPromiseLike = obj => obj !== null && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function';
console.log(isPromiseLike({
then: function() {
return '';
}
}));
console.log(isPromiseLike(null));
console.log(isPromiseLike({}));
➜ code git:(master) ✗ node isPromiseLike.js
true
false
false
isString
Checks if the given argument is a string.
Use
typeof
to check if a value is classified as a string primitive.const isString = val => typeof val === 'string';
检测一个变量是否是 string
类型。
用 typeof
进行检测即可。
➜ code git:(master) ✗ cat isString.js
const isString = val => typeof val === 'string';
console.log(isString('10'));
console.log(isString(10));
console.log(isString(true));
➜ code git:(master) ✗ node isString.js
true
false
false
isSymbol
Checks if the given argument is a symbol.
Use
typeof
to check if a value is classified as a symbol primitive.const isSymbol = val => typeof val === 'symbol';
检测一个变量是否是 symbol
类型。
用 typeof
进行检测即可。
➜ code git:(master) ✗ cat isSymbol.js
const isSymbol = val => typeof val === 'symbol';
console.log(isSymbol('x'));
console.log(isSymbol(Symbol('x')));
➜ code git:(master) ✗ node isSymbol.js
false
true
isValidJSON
Checks if the provided argument is a valid JSON.
Use
JSON.parse()
and atry... catch
block to check if the provided argument is a valid JSON.const isValidJSON = obj => { try { JSON.parse(obj); return true; } catch (e) { return false; } };
检测一个变量是否是合法的 JSON
。
使用 JSON.parse()
结合 try… catch
对变量进行判断,如果能正确解析返回 true
,否则返回 false
。
➜ code git:(master) ✗ cat isValidJSON.js
const isValidJSON = obj => {
try {
JSON.parse(obj);
return true;
} catch (e) {
return false;
}
};
console.log(isValidJSON('{"name":"Adam","age":20}'));
console.log(isValidJSON('{"name":"Adam",age:"20"}'));
console.log(isValidJSON(null));
➜ code git:(master) ✗ node isValidJSON.js
true
false
true
isStrictNaN
const isStrictNaN = val => val !== val;
这个方法是我自己加的,有时候需要判断是不是 NaN
,NaN
有一个独特的特性是它不等于它本身。这个方法和 isNaN
有什么不同,可以看 NDN
的 isNaN
。
➜ code git:(master) ✗ cat isStrictNaN.js
const isStrictNaN = val => val !== val;
console.log(isStrictNaN(NaN));
console.log(isStrictNaN('a'));
console.log(isStrictNaN(null));
console.log(isStrictNaN(undefined));
console.log(isStrictNaN(true));
➜ code git:(master) ✗ node isStrictNaN.js
true
false
false
false
false
终极大法
一般来说,大家如果不用 underscore
或者 lodash
的话,通常都是用以下方法进行判断的:
const isType = val => Object.prototype.toString.call(val).slice(8, -1).toLowerCase();
或者是正则:
const isType = val => Object.prototype.toString.call(val).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
这块就不用给例子了,有心人会自己去试。
一般我倾向于使用第一种,因为用正则一是比较难读懂,二是速度比较慢,实在是不用正则不能解决问题的时候才会用。
以上的方法是终极大法,但速度会比较慢,所以对于能直接用 typeof
进行判断的类型,通常直接用 typeof
即可。不考虑运行效率的话,以上方法自然是一劳永逸。
不错
多谢鼓励
不错。。大赞 。。个人觉得:带着情绪去反对别人的观点是很不聪明的。。。做技术就需要这种务实的氛围。
严格判断 nan 有个标准方法 Number.isNaN()
@Yangk030208 没错,提升技术能力是关键,不要为了吵而吵
@waitingsong 多谢,又学习了
之前就在想,写代码的时候,内部的类型判断有需求再去判断就可以了。别人传错了,就报错。外部的,比如服务返回,是不是写个data modal做强校验
大多数我喜欢用原生的,写起来也不麻烦
[CNodeMD]
@dbit-xia 这看个人水平了,一般经验不太足的写不出来,或者各种边界考虑不全,容易有bug
@gxy01 感觉你是在陈述事实,知道怎么做,做什么样合理并实施就行,条条大路通罗马