Description
将目光放在 es6 之前 js 类型有六种 Undefined null String Number Boolean Object
Object 类型中包含着 函数 、日期 、正则 、数组、(数组和类数组) 错误类型; 如果再将 Object 细分一下还会有 planinObject 空对象 Window对象等
除此之外还有 Math Json 类型
常用的类型判断方法会使用 typeof
console.log(typeof 'abc') // string
使用 typeof 会返回 undefined、object、boolean、number、string、object 和 function
在面对其他类型时 如 数组或者正则 typeof 只能返回 object 这时候要采取其他的方法来判断
Object.prototype.toString
当 toString 方法被调用的时候,下面的步骤会被执行:
- 如果 this 值是 undefined,就返回 [object Undefined]
- 如果 this 的值是 null,就返回 [object Null]
- 让 O 成为 ToObject(this) 的结果
- 让 class 成为 O 的内部属性 [[Class]] 的值
- 最后返回由 "[object " 和 class 和 "]" 三个部分组成的字符串
// 最后返回的结果 "[object " 和 class 和 "]"
console.log(Object.prototype.toString.call(date)) // [object Date]
使用 Object.prototype.toString 我们至少可以识别 14种类型
var number = 1; // [object Number]
var string = '123'; // [object String]
var boolean = true; // [object Boolean]
var und = undefined; // [object Undefined]
var nul = null; // [object Null]
var obj = {a: 1} // [object Object]
var array = [1, 2, 3]; // [object Array]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function a(){}; // [object Function]
console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]
function a() {
console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
}
//甚至还有
Object.prototype.toString.call(window)
"[object Window]"
Object.prototype.toString.call(document);
"[object HTMLDocument]"
照抄一个判断类型
var class2type = {};
// 判断11种类型 生成一组映射
"Boolean Number String Function Array Date RegExp Object Error Null Undefined".split(" ").map(function(item, index) {
class2type["[object " + item + "]"] = item.toLowerCase();
})
function type(obj) {
// IE6中 null 和 undefined 返回的时 [object object] 而且 null == undefined
if(obj == null){
return obj + '';
}
return typeof obj === 'object' || typeof obj === 'function' ?
class2type[Object.prototype.toString.call(obj)] || 'object':
typeof obj
}
// 判断数组 也可以使用 Array.isArray()
var isArray = Array.isArray || function(obj){
return type(obj) === 'array';
}
判断数据类型的type函数的扩展性不太好类似像window
location
navigator
document
都会返回object
function type(obj) {
if(typeof obj !== 'object' || typeof obj === 'function'){
return typeof obj;
}else{
return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}
}
数字(Number)中 再一次的划分整数、NaN、-0、0 、浮点数、Infinity、-Infinity
// 判断 NaN 它不和自身相等
let isNaN = Number.isNaN || (obj) => (obj !== obj)
//有穷正数/infinity = 0
//有穷负数/infinity = -0
0 === -0 // true
-3/0 // -0
let is = Object.is || function(v1,v2){
// 判断是否是 -0;
if(v1 === 0 && v2 === 0) {
return 1/v1 === 1/v2;
}
// 判断NaN
if(v1 !== v1 ) {
return v2 !== v2
}
return v1 === v2
}
关于类型判断我们还可以使用这些方法:
- typeof
- constructor
- instanceof
- Object.prototype.toString
plainObject
可以翻译成纯粹的对象,所谓"纯粹的对象",就是该对象是通过 "{}" 或 "new Object" 创建的,该对象含有零个或者多个键值对。除了 {} 和 new Object 创建的之外,jQuery 认为一个没有原型的对象也是一个纯粹的对象。
var class2type = {};
// 相当于 Object.prototype.toString
var toString = class2type.toString;
// 相当于 Object.prototype.hasOwnProperty
var hasOwn = class2type.hasOwnProperty;
function isPlainObject(obj) {
var proto, Ctor;
// 排除掉明显不是obj的以及一些宿主对象如Window
if (!obj || toString.call(obj) !== "[object Object]") {
return false;
}
/**
* getPrototypeOf es5 方法,获取 obj 的原型
* 以 new Object 创建的对象为例的话
* obj.__proto__ === Object.prototype
*/
proto = Object.getPrototypeOf(obj);
// 没有原型的对象是纯粹的,Object.create(null) 就在这里返回 true
if (!proto) {
return true;
}
/**
* 以下判断通过 new Object 方式创建的对象
* 判断 proto 是否有 constructor 属性,如果有就让 Ctor 的值为 proto.constructor
* 如果是 Object 函数创建的对象,Ctor 在这里就等于 Object 构造函数
*/
Ctor = Object.prototypr.hasownProperty.call(proto, "constructor") && proto.constructor;
// 在这里判断 Ctor 构造函数是不是 Object 构造函数,用于区分自定义构造函数和 Object 构造函数
return typeof Ctor === "function" && hasOwn.toString.call(Ctor) === obj.toString.call(Object);
}
注意:我们判断 Ctor 构造函数是不是 Object 构造函数,用的是 hasOwn.toString.call(Ctor),这个方法可不是 Object.prototype.toString,不信我们在函数里加上下面这两句话:
//举例子:
var p = function () {}
console.log(p.toString.call(Ctor)); // function Object() { [native code] }
console.log(Object.prototype.toString.call(p)); // [object Function]
发现返回的值并不一样,这是因为 hasOwn.toString 调用的其实是 Function.prototype.toString,毕竟 hasOwnProperty 可是一个函数!
hasOwn.toString.call(Ctor) === hasOwn.toString.call(Object)
//可以换成
Ctor.toString.call(Ctor) === class2type.constructor.toString.call(Object)
空对象
function isEmptyObject( obj ) {
var name;
//for 循环一旦执行,就说明有属性,有属性就会返回 false。
for ( name in obj ) {
return false;
}
return true;
}
isEmptyObject('') //true 还是存在点问题(这里默认你传进来的参数时对象并没有判断类型)
Window对象
function isWindow (obj){
//Window 对象作为客户端 JavaScript 的全局对象,它有一个 window 属性指向自身
return obj ! = null && obj === obj.window
}
判断是否是数组(数组和类数组)
function isArrayLike(obj) {
// obj 必须有 length属性
var length = !!obj && "length" in obj && obj.length;
var typeRes = type(obj);
// 排除掉函数和 Window 对象
if (typeRes === "function" || isWindow(obj)) {
return false;
}
return typeRes === "array" || length === 0 ||
// 长度必须是数字 或者长度大于0 或者最后一个值必须存在
typeof length === "number" && length > 0 && (length - 1) in obj;
}
//另外的版本
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var isArrayLike = function(collection) {
var length = getLength(collection);
// 长度必须是数字并且长度大于0并且长度小于最大长度
return typeof length == 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
};
es6 以后 类型又增加了 Symbol Set Map 还有ES2020中 BigInt
var symb = Symbol('test'); // [object Symbol]
var set = new Set(); // [object Set]
var map = new Map(); // [object Map]
var bigI = BigInt(1); // [object BigInt]