关于typeof和instanceOf

typeof

typeof,一元运算符号,返回值是一个字符串,说明运算数的类型(UndefinedNullBooleanNumberString。ES6中增加了一种Symbol。)。
然而,typeof几乎不可能得到它们想要的结果。因为他真的是只能获取几个基本对象的类型,可对于我们大多时候使用的数组,函数等错综复杂的对象,他统一都给你返回Object(;′⌒′ )

我们做一个实验:
首先我们知道,在js中要真正获取对象的类型一般是采用Object.prototype.toSring.call()这个方法的(什么你不知道Σ( ° △ °|||)︴,那现在知道了吧,好奇宝宝请自行搜索其原理),然后我们对一些常用的对象类型进行检测:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

function check(x) {
console.log( x + " ,typeof: " + typeof(x) + " ,class: " + Object.prototype.toString.call(x));
}

check("abc");
check(new String("abc"));
check(1.2);
check(new Number(1.2));
check(true);
check(new Boolean(true));
check([1,2,3]);
check(new Array(1,2,3));
check(/abc/g);
check(new RegExp("/abc/g"));
check({});
check(new Object());
check(new Function(""));
check(new Date());
check(new Error());
check(undefined);

对于结果我做了一个表格来对比
| value | type | [[class]] |
|: — :|: — :|: — :|
|”abc”|string |[object String]|
|new String(“abc”)|object |[object String]|
|1.2|number|[object Number]|
|new Number(1.2)|object |[object Number]|
|true|boolean |[object Boolean]|
|new Boolean(true)|object |[object Boolean]|
|[1,2,3]|object |[object Array]|
|new Array(1,2,3)|object |[object Array]|
|/abc/g|object |[object RegExp]|
|new RegExp(“/abc/g”)|object |[object RegExp]|
|{})|object |[object Object]|
|new Object()|object |[object Object]|
|new Function(“”)|function |[object Function]|
|new Date()|object |[object Date]|
|new Error() |object |[object |
|undefined|undefined|[object Undefined]|

所以,如果你想检测一个对象的类型,还是用Object.prototype.toString吧,因为这是唯一一个可以依赖的方法。

instanceof

instanceof 左操作数是一个类,右操作数是标识对象的类。如果左侧的对象是右侧类的实例,则返回true
而js中对象的类是通过初始化它们的构造函数来定义的,即instanceof的右操作数应当是一个函数。所有的对象都是object的实例。如果左操作数不是对象,则返回false,如果右操作数不是函数,则抛出typeError。
instanceof 运算符是用来测试一个对象是否在其原型链原型构造函数的属性。其语法是object instanceof constructor
instanceof操作符用来比较两个操作数的构造函数。只有在比较自定义的对象时才有意义。 如果用来比较内置类型,将会和typeof操作符 一样用处不大。

比较自定义对象:

1
2
3
4
5
6
7
8
9
10
function Foo() {}
function Bar() {}
Bar.prototype = new Foo();

new Bar() instanceof Bar; // true
new Bar() instanceof Foo; // true

// 如果仅仅设置 Bar.prototype 为函数 Foo 本身,而不是 Foo 构造函数的一个实例
Bar.prototype = Foo;
new Bar() instanceof Foo; // false

instanceof 比较内置类型:

1
2
3
4
5
new String('foo') instanceof String; // true
new String('foo') instanceof Object; // true

'foo' instanceof String; // false
'foo' instanceof Object; // false

总之,instanceof 用来比较属于不同 JavaScript 上下文的对象(比如,浏览器中不同的文档结构)时将会出错, 因为它们的构造函数不会是同一个对象。
所以instanceof 操作符应该仅仅用来比较来自同一个 JavaScript 上下文的自定义对象。 正如 typeof 操作符一样,任何其它的用法都应该是避免的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function C(){} // defining a constructor
function D(){} // defining another constructor

var o = new C();
o instanceof C; // true, because: Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false, because D.prototype is nowhere in o's prototype chain
o instanceof Object; // true, because:
C.prototype instanceof Object // true

C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false, because C.prototype is nowhere in o's prototype chain anymore

D.prototype = new C(); // use inheritance
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true