数据类型

  • 6种原始类型(primitives)
    • null
    • undefined
    • Boolean
    • Number
    • String
    • Symbol(ECMAScript6新定义)
  • Object

typeof

语法

typeof operand

typeof操作符返回一个字符串,代表表达式的类型。

常见的typeof返回值。

1
2
3
4
5
6
7
8
typeof undefined === "undefined"; // true
typeof true === "boolean"; // true
typeof 42 === "number"; // true
typeof "42" === "string"; // true
typeof { life: 42 } === "object"; // true
// added in ES6!
typeof Symbol() === "symbol"; // true

使用typeof操作符的时候有一些特例,上面并没有列出,下面逐个解释。

null

1
typeof null === "objects"; // true

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null的类型标签也成为了 0,typeof null就错误的返回了”object”。ECMAScript提出了一个修复(通过opt-in),但被拒绝。这将导致typeof null === ‘object’。

如果想要测试为null的value的type,可以使用如下方法:

1
2
3
var a = null;
(!a && typeof a === "object"); // true

function

1
typeof function a(){ /* .. */ } === "function"; // true

因为[[Call]] 在ECMA-262条款中实现了,function包含[[Call]]属性,它允许function被调用,function可以理解为object的子类型。

array

1
typeof [1,2,3] === "object"; // true

数组同样可以被认为是object的子类型。

使用new操作符

1
2
3
4
5
6
7
8
var str = new String('String');
var num = new Number(100);
typeof str; // It will return 'object'
typeof num; // It will return 'object'
var func = new Function();
typeof func; // It will return 'function'

instanceof

语法

object instanceof constructor

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

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();
o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototype
o instanceof D; // false,因为 D.prototype不在o的原型链上
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

需要注意的是,如果表达式 obj instanceof Foo 返回true,则并不意味着该表达式会永远返回true,因为Foo.prototype属性的值有可能会改变,改变之后的值很有可能不存在于obj的原型链上,这时原表达式的值就会成为false。另外一种情况下,原表达式的值也会改变,就是改变对象obj的原型链的情况,虽然在目前的ES规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的proto魔法属性,是可以实现的。比如执行obj.proto = {}之后,obj instanceof Foo就会返回false了。

Array

1
2
3
4
var isArray = Array.isArray ||
function(obj) { return obj instanceof Array } ||
function(obj) { return Object.prototype.toString.call(obj) === "[object Array]" } ||
function(obj) { return Array.prototype.isPrototypeOf(obj) }

Number

1
2
3
4
5
6
7
8
9
var isNumber = function(obj) { return typeof obj === "number" } ||
function(obj) { return obj instanceof Number } ||
function(obj) { return Object.prototype.toString.call(obj) === "[object Number]" } ||
function(val) {
var num = Number(val), type = typeof val
return val != null && type != 'boolean' &&
(type != 'string' || val.length) &&
!isNaN(num) && isFinite(num) || false
}

Object

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
var class2type = {}, toString = class2type.toString
function likeArray(obj) {
return obj.length ? true : false
}
function each(elements, callback) {
var i, key
if (likeArray) {
for (i = 0; i < elements.length; i++) {
if (callback.call(elements[i], i, elements[i]) === false) return elements
}
} else {
for (key in elements) {
if (callback.call(elements[key], i, elements[key]) === false) return elements
}
}
return elements
}
each("Boolean Number String Function Array Data RegExp Object Error".split(" "), function(i, name) {
class2type[ "[object " + name + "]" ] = name.toLowerCase()
})
function type(obj) {
return obj == null ? String(obj) :
class2type[toString.call(obj)] || "object"
}
function isObject(obj) { return type(obj) == "object" }

参考:
https://github.com/getify/You-Dont-Know-JS/blob/master/types%20%26%20grammar/ch1.md
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/typeof
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Data_structures
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/instanceof
《JavaScript高级程序设计》