Javascript判断数据类型的五种方式及其特殊性

Javascript判断数据类型的五种方式及区别

@

————-人工分割线————-

typeof

MDN:typeof操作符返回一个字符串,表示未经计算的操作数的类型。

    let data = {
        number : 1,
        string : 'b',
        boolean : true,
        symbol : Symbol(),
        null : null,
        undefined : undefined,
        nan : NaN,
        function : function (){},
        object : {},
        array: [],
    };

    for(let key in data) {
        console.log(key + ':::', typeof data[key]);
    }
    // -----------  打印结果  ------------------
    number::: number
    string::: string
    boolean::: boolean
    symbol::: symbol
    null::: object          // 需要注意
    undefined::: undefined
    nan::: number           // 需要注意
    function::: function
    object::: object
    array::: object         // 需要注意

null、array:打印结果都是object
NaN:打印结果是number

关于null打印成object的原因:属于JS遗留bug,在一开是的JS版本种使用32位系统,为了提高性能使用低位存储变量的类型信息,所以将000 开头代表是对象,但是 null 表示为全零,所在在判断null时也会将它错误的判断为 object 。

instanceof

MDN:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上

 	function Animal(name) {
        this.name = name;
    }

    let cat = new Animal('cat');
    let dog = new Animal('dog');
    console.log(cat instanceof Animal);
    console.log(cat instanceof dog); // 报错:Right-hand side of 'instanceof' is not callable
    

instanceof的右边要求是一个构造函数,否则报错。

如何理解:instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上??

::: 如:cat instanceof Animal:Animal.prototype是否在cat的原型链上【Animal–Object】,显然是在的,所以返回true。

思考:

    function Animal(name) {
        this.name = name;
    }
    let cat = new Animal('cat'); //
	// 此时将Animal.prototype指向空对象
	let A = {};
    Animal.prototype = A;
    let cat2 = new Animal('cat2');
    console.log(cat instanceof Animal);
    console.log(cat2 instanceof Animal);

此时应该打印什么?

先分析cat的原型链:【Animal — Object】
cat2的原型链:【A — Object】
此时Animal.prototype指向A对象,所以A在cat2的原型链上,而不在cat上。


所以打印结果:
false
true

总结:先找到Animal.prototype,在列出cat的原型链,如果在就true否则false。

特殊点:
1:instanceof 和多全局对象(例如:多个 frame 或多个 window 之间的交互)
不同的全局环境拥有不同的全局对象,从而拥有不同的内置类型构造函数。这可能会引发一些问题。比如,表达式 [] instanceof window.frames[0].Array 会返回 false,因为 Array.prototype !== window.frames[0].Array.prototype,并且数组从前者继承。

2: String 对象和 Date 对象都属于 Object 类型和一些特殊情况

    let simpleStr = 'simpleStr';
    let myObj = {};
    let myNullObj = Object.create(null);
    console.log(simpleStr instanceof String); //false [检查原型链会找到 undefined]
    console.log(myObj instanceof Object);     //true
    console.log(myNullObj instanceof Object); //false [一种创建非 Object 实例的对象的方法]

Object.prototype.toString

MDN:方法返回一个表示该对象的字符串。

// 数据源看开头的代码
 for(let key in data) {
        console.log(key + ':::', Object.prototype.toString.call(data[key]));
    }
    /*
        number::: [object Number]
        string::: [object String]
        boolean::: [object Boolean]
        symbol::: [object Symbol]
        null::: [object Null]
        undefined::: [object Undefined]
        nan::: [object Number]  // 需要注意
        function::: [object Function]
        object::: [object Object]
        array::: [object Array]
    * */
  • 为了每个对象都能通过 Object.prototype.toString() 来检测,需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg。

  • Object.prototype.toString 的原理是当调用的时候, 就取值内部的 [[Class]] 属性值, 然后拼接成 ‘[object ‘ + [[Class]] + ‘]’ 这样的字符串并返回. 然后我们使用 call 方法来获取任何值的数据类型.

isArray

MDN:如果对象是 Array ,则返回true,否则为false。
这个比较简单不写例子了。

特殊性:当检测Array实例时, Array.isArray 优于 instanceof,因为Array.isArray能检测iframes.

var iframe = document.createElement('iframe');
document.body.appendChild(iframe);
xArray = window.frames[window.frames.length-1].Array;
var arr = new xArray(1,2,3); // [1,2,3]

// Correctly checking for Array
Array.isArray(arr);  // true
// Considered harmful, because doesn't work though iframes
arr instanceof Array; // fals

iisNaN

MDN:用来确定一个值是否为NaN 。注:isNaN函数内包含一些非常有趣的规则;你也可以使用 ECMAScript 2015 中定义的 Number.isNaN() 来判断。与 JavaScript 中其他的值不同,NaN不能通过相等操作符(== 和 ===)来判断 ,因为 NaN == NaN 和 NaN === NaN 都会返回 false。 因此,isNaN 就很有必要了。

isNaN(NaN);       // true
isNaN(undefined); // true
isNaN({});        // true

isNaN(true);      // false
isNaN(null);      // false
isNaN(37);        // false

// strings
isNaN("37");      // false: 可以被转换成数值37
isNaN("37.37");   // false: 可以被转换成数值37.37
isNaN("37,5");    // true
isNaN('123ABC');  // true:  parseInt("123ABC")的结果是 123, 但是Number("123ABC")结果是 NaN
isNaN("");        // false: 空字符串被转换成0
isNaN(" ");       // false: 包含空格的字符串被转换成0

// dates
isNaN(new Date());                // false
isNaN(new Date().toString());     // true

isNaN("blabla")   // true: "blabla"不能转换成数值
                  // 转换成数值失败, 返回NaN

一个有用的特性:
有许多方式来看待isNaN():如果isNaN(x)返回false,那么x在任何算数表达式中都不会使表达式等于NaN;如果返回true,x会使所有算数表达式返回NaN。这就意味着,在JavaScript中,isNaN(x)==true等价于x-0=NaN(在JavaScript中 x-0 == NaN 总是返回false,所以你不用去测试它)。

实际上, isNaN(x), isNaN(x – 0),isNaN(Number(x)), Number.isNaN(x – 0),和Number.isNaN(Number(x)) 的返回值都是一样的 并且在JavaScript中isNaN(x)是这些表达式中最短的表达。