# javascript中如何判断变量类型?

# typeof

判断基本类型,返回一个字符串

typeof 123 === 'number' // true
类型 结果
Undefined "undefined"
Null "object"(见下文)
Boolean "boolean"
Number "number"
String "string"
Symbol (ECMAScript 6 新增) "symbol"
宿主对象(由JS环境提供) Implementation-dependent
函数对象([[Call]] 在ECMA-262条款中实现了) "function"
任何其他对象 "object"

# instanceof

检查某个对象属于哪个构造函数

function A(){}
let a = new A()

a instanceof A // true

# 更详细的解释

由于具体实现上的问题,在实际的项目应用中,typeof只有两个用途,就是检测一个元素是否为undefined,或者是否为function。

# 为何呢?

JavaScript Garden整理出来了如下表格:

Value function typeof
"foo" String string
new String("foo") String object
1.2 Number number
new Number(1.2) Number object
true Boolean boolean
new Boolean(true) Boolean object
new Date() Date object
new Error() Error object
[1,2,3] Array object
new Array(1, 2, 3) Array object
new Function("") Function function
/abc/g RegExp object
new RegExp("meow") RegExp object
{} Object object
new Object() Object object

所以我们一般用“鸭子类型”来做流程控制。

# 一定要区分这些东西?

Object.prototype.toString()有一个妙用,如果我们以某个特别的对象为上下文来调用该函数,它会返回正确的类型。我们需要做的就是手动处理其返回的字符串,最终便能获得typeof应该返回的正确字符串。

可以用来区分:Boolean, Number, String, Function, Array, Date, RegExp, Object, Error等等。

jQuery.type()就是这样实现的。以下代码从jQuery源码中抽取出来,可以直接用。

var class2type = {} ;
"Boolean Number String Function Array Date RegExp Object Error".split(" ").forEach(function(e,i){
    class2type[ "[object " + e + "]" ] = e.toLowerCase();
}) ;
//当然为了兼容IE低版本,forEach需要一个polyfill,不作细谈了。
function _typeof(obj){
    if ( obj == null ){
        return String( obj );
    }
    return typeof obj === "object" || typeof obj === "function" ?
        class2type[ class2type.toString.call(obj) ] || "object" :
        typeof obj;
}

使用结果:

_typeof(new String())
->"string"
_typeof("123")
->"string"
_typeof(new RegExp())
->"regexp"
_typeof(null)
->"null"
# 公认的方法

即使都是object类型,也还是有区分的。比如[object Object] [object String]... Object.prototype.toString.call(x) === '[object Array]'

# 鸭子类型

  • js是一门动态语言,指的是在运行过程中可以改变其结构等。 比如var a=0 a='3'+5
  • 鸭子类型是动态类型的一种风格。在这种风格中,一个对象有效的语义,不是由继承自特定的类或实现特定的接口,而是由“当前方法和属性的集合”决定。
  • 当看到一只鸟走起来像鸭子,游泳像鸭子,叫起来像鸭子,那么这只鸟就可以被称之为鸭子。
  • 在鸭子类型中,关注点在于对象的行为,能做什么,而不是关注类型。
  • 可以理解为,在不继承的情况下使用了多态。
// 应聘选手鸭子
let duck = {
    voice: '嘎嘎嘎'
}
// 应聘选手鸡
let chicken = {
    voice: '嘎嘎嘎'
}
// 合唱团成员数组
let choir = []
// 加入合唱团
function joinChoir(animal) {
    console.log(animal.voice)
    if(animal.voice === '嘎嘎嘎') {
        choir.push(animal)
    }
}
// 鸭子加入
joinChoir(duck)
// 鸡加入
joinChoir(chicken)
// 合唱团组队完成
console.log(choir)
# 参考资料

JavaScript instanceof 运算符深入剖析

如何正确判断js类型

动态语言与鸭子类型