JS类型判定

js有六种基本类型:number, string, bool, null, undefined,symbol。还有复杂类型:Array、Function、Object等。
在js中常见类型检查手段的区别:typeof, instanceof, toString。
如果你要判断的是基本数据类型或JavaScript内置对象,使用toString; 如果要判断的时自定义类型,请使用instanceof。

  1. typeof
    typeof 操作符返回的是类型字符串,它的返回值有6种取值:

    1
    2
    3
    4
    5
    6
    7
    typeof 3 // "number"
    typeof "abc" // "string"
    typeof {} // "object"
    typeof true // "boolean"
    typeof undefined // "undefined"
    typeof function(){} // "function"
    typeof function(){} // "function"
  2. instanceof
    instanceof操作符用于检查某个对象的原型链是否包含某个构造函数的prototype属性。
    instanceof是通过原型链来检查类型的,所以适用于任何”object”的类型检查。

    1
    2
    3
    4
    5
    6
    7
    // 比如直接原型关系
    function Animal(){ }
    (new Animal) instanceof Animal // true
    // 原型链上的间接原型
    function Cat(){}
    Cat.prototype = new Animal
    (new Cat) instanceof Animal // true

instanceof也可以用来检测内置兑现,比如Array, RegExp, Object, Function:

1
2
3
4
[1, 2, 3] instanceof Array // true
/abc/ instanceof RegExp // true
({}) instanceof Object // true
(function(){}) instanceof Function // true

但你可以这样:

1
2
3
new Number(3) instanceof Number // true
new Boolean(true) instanceof Boolean // true
new String('abc') instanceof String // true

但这时你已经知道数据类型了,类型检查已经没有意义了。

  1. toString
    toString方法是最为可靠的类型检测手段,它会将当前对象转换为字符串并输出。 toString属性定义在Object.prototype上,因而所有对象都拥有toString方法。 但Array, Date等对象会重写从Object.prototype继承来的toString, 所以最好用Object.prototype.toString来检测类型。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    toString = Object.prototype.toString;
    toString.call(new Date); // [object Date]
    toString.call(new String); // [object String]
    toString.call(Math); // [object Math]
    toString.call(3); // [object Number]
    toString.call([]); // [object Array]
    toString.call({}); // [object Object]
    toString.call(function q(){}); // [object Function]
    toString.call(new RegExp('a')); // [object RegExp]
    // Since JavaScript 1.8.5
    toString.call(undefined); // [object Undefined]
    toString.call(null); // [object Null]

toString也不是完美的,它无法检测用户自定义类型。 因为Object.prototype是不知道用户会创造什么类型的, 它只能检测ECMA标准中的那些内置类型。

  1. 总结
    typeof只能检测基本数据类型,对于null还有Bug;
    instanceof适用于检测对象,它是基于原型链运作的;
    toString适用于ECMA内置JavaScript类型(包括基本数据类型和内置对象)的类型判断;

对象遍历属性

顺便说一说关于对象遍历属性的几种方法。

  1. 遍历可枚举的、自身的属性
    使用 Object.keys() 或是 for..in + hasOwnProperty()。
    Object.keys()是获取当前对象的所有可枚举、自身的属性;
    for..in是获取当前对象包括原型链上的所有可枚举属性;
    hasOwnProperty是判断某个属性是否在当前对象上。
    1
    2
    3
    4
    // 再用for..of对返回的数组进行遍历
    for (let prop of Object.keys(p1)){
    console.log(prop);
    }
1
2
3
4
5
6
7
// 得到可枚举、自身+继承的属性
for (let prop in p1) {
// 过滤继承属性
if (p1.hasOwnProperty(prop)) {
console.log(prop);
}
}
  1. 遍历所有(可枚举的&不可枚举的)、自身的属性
    Object.getOwnPropertyNames方法返回一个由指定对象的所有自身属性的属性名(包括不可枚举属性但不包括Symbol值作为名称的属性)组成的数组。要获取属性为Symbols类型的只能通过Object.getOwnPropertySymbols

    1
    2
    3
    4
    // 使用 `Object.getOwnPropertyNames()`
    for (let prop of Object.getOwnPropertyNames(p1)) {
    console.log(prop);
    }
  2. 遍历可枚举的、自身+继承的属性

    1
    2
    3
    4
    // 使用 `for..in`
    for (let prop in p1) {
    console.log(prop);
    }
  3. 遍历所有的、自身+继承的属性

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    var getAllPropertyNames = (obj) => {
    var props = [];
    do {
    props = props.concat(Object.getOwnPropertyNames(obj));
    } while (obj = Object.getPrototypeOf(obj));
    return props;
    };
    for (let prop of getAllPropertyNames(p1)) {
    console.log(prop);
    }