Skip to content

JavaScript 的类型判断 #1

Open
@xiaochengzi6

Description

@xiaochengzi6

将目光放在 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 方法被调用的时候,下面的步骤会被执行:

  1. 如果 this 值是 undefined,就返回 [object Undefined]
  2. 如果 this 的值是 null,就返回 [object Null]
  3. 让 O 成为 ToObject(this) 的结果
  4. 让 class 成为 O 的内部属性 [[Class]] 的值
  5. 最后返回由 "[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
}

关于类型判断我们还可以使用这些方法:

  1. typeof
  2. constructor
  3. instanceof
  4. 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]

参考

JavaScript 类型判断(上)

JavaScript 类型判断(下)

Metadata

Metadata

Assignees

No one assigned

    Labels

    JavaScriptJavaScript 语言的学习

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions