manlili blog

typeof VS instanceof

这次主要说说JavaScript的类型判断函数typeof和判断构造函数原型instanceof的用法和注意的地方。

typeof

我们先看看各个数据类型对应typeof的值
| 数据类型 | Type |
| ——– | —–: |
| Undefined | undefined |
| Null | object (注意这里) |
| Boolean | boolean |
| Number | number |
| String | string |
| Symbol | symbol |
| Function | function |
| other Object | object |
需要注意Type都是小写字母

下面来看看具体的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// Numbers
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管NaN是"Not-A-Number"的缩写,意思是"不是一个数字"
typeof Number(1) === 'number'; // 不要这样使用!
// Strings
typeof "" === 'string';
typeof "bla" === 'string';
typeof (typeof 1) === 'string'; // typeof返回的肯定是一个字符串
typeof String("abc") === 'string'; // 不要这样使用!
// Booleans
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(true) === 'boolean'; // 不要这样使用!
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof blabla === 'undefined'; // 一个未定义的变量,或者一个定义了却未赋初值的变量
// Objects
typeof {a:1} === 'object';
// 使用Array.isArray或者Object.prototype.toString.call方法可以从基本的对象中区分出数组类型
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
// 下面的容易令人迷惑,不要这样使用!
typeof new Boolean(true) === 'object';
typeof new Number(1) ==== 'object';
typeof new String("abc") === 'object';
// 函数
typeof function(){} === 'function';
typeof Math.sin === 'function';

我们会发现一个问题,就是typeof来判断数据类型其实并不准确。比如数组、正则、日期、对象的typeof返回值都是object,这就会造成一些误差。
所以在typeof判断类型的基础上,我们还需要利用Object.prototype.toString方法来进一步判断数据类型。

我们来看看在相同数据类型的情况下,toString方法和typeof方法返回值的区别:
| 数据类型 | toString | typeof |
| ——– | —–: | :—-: |
| Date | Date | object |
| Array | Array | object |
| Function | Function | object |
| RegExp | RegExp | object |

下面来看看Object.prototype.toString实例

1
2
3
4
5
var o = new Object();
o.toString(); // returns [object Object]注意如果是Object标准格式可以直接用toString
var o = new Date();
Object.prototype.toString.call(o); // returns [object Date],如果不是Object标准格式,需要Object.prototype.toString.call

instanceof

instanceof运算符可以用来判断某个构造函数的prototype属性是否存在于另外一个要检测对象的原型链上.
| 数据类型 | instanceof |
| ——– | —–: |
| Date | Date |
| Array | Array |
| Function | Function |
| RegExp | RegExp |
需要注意你上面都是首字母大写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// 定义构造函数
function C(){}
function D(){}
var o = new C();
// true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof C;
// false,因为 D.prototype不在o的原型链上
o instanceof D;
o instanceof Object; // true,因为Object.prototype.isPrototypeOf(o)返回true
C.prototype instanceof Object // true,同上
C.prototype = {};
var o2 = new C();
o2 instanceof C; // true
o instanceof C; // false,C.prototype指向了一个空对象,这个空对象不在o的原型链上.
D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true

继承中判断实例是否属于它的父类

1
2
3
4
5
6
function Ben_parent() {}
function Ben_son() {}
Ben_son.prototype = new Ben_parent();//原型继承
var ben_son = new Ben_son();
console.log(ben_son instanceof Ben_son);//true
console.log(ben_son instanceof Ben_parent);//true

复杂用法

1
2
3
4
5
6
7
8
9
function Ben() {}
console.log(Object instanceof Object); //true
console.log(Function instanceof Function); //true
console.log(Function instanceof Object); //true
console.log(Ben instanceof Function); //true
console.log(String instanceof String); //false 因为五大基本数据类型不能用instanceof
console.log(Boolean instanceof Boolean); //false 因为五大基本数据类型不能用instanceof
console.log(Ben instanceof Ben); //false

A instanceof B :检测B.prototype是否存在于参数A的原型链上.

1
2
3
4
5
function Ben() {
}
var ben = new Ben();
console.log(ben instanceof Ben);//true

对于上面的instanceof我们可以写个函数来模拟一下

1
2
3
4
5
6
7
8
9
10
11
12
function _instanceof(A, B) {
var O = B.prototype;// 取B的显示原型
A = A.__proto__;// 取A的隐式原型
while (true) {
//Object.prototype.__proto__ === null
if (A === null)
return false;
if (O === A)// 这里重点:当 O 严格等于 A 时,返回 true
return true;
A = A.__proto__;
}
}

请我喝杯果汁吧!