JS 中有 7 种内置数据类型:
- Undefined(未定义)
- Null(空值)
- Number(数字)
- String(字符串)
- Boolean(布尔值)
- Symbol(符号) [ ES6 新增,详情见 ES6 入门 ]
- Object(对象)
上述 7 种类型,除了 Object 外都是基本数据类型。
检测数据类型的方法
1. typeof(返回类型的字符串)
- typeof undefined // undefined
- typeof true // boolean
- typeof 42 // number
- typeof ‘42’ // string
- typeof { life: 42} // object
- typeof Symbol() // symbol
以上 6 种类型均有同名的字符串与之对应,接下来我们看 null:
- typeof null // object
之所以对 null 调用 typeof 返回 object,是因为特殊值 null 被认为是一个空的对象的引用。
还有以下几种情况:
- typeof function a() { // } // function
- typeof [1, 2, 3] // object
- typeof /<\w+?>/ // function || object
这样看来的话
function(函数)也是 JS 的一个内置类型?它实际上是 object 的一个子类型。具体来说,函数是“可调用对象”,它内部有一个 [[Call]] 属性,可以使其被调用。所以用 typeof 区分函数和其他对象是有必要的。
array(数组)也是对象。确切地说,它也是 object 的一个“子类型”,数组的元素按数字顺序来进行索引(而非普通像对象那样通过字符串键值),其 length 属性是元素个数。
regexp(正则表达式)也是对象。准确描述,Chrome 7 及之前版本在此返回 function,而其他浏览器返回 object
JS 中,对于未赋值或者未定义的变量,使用 typeof 操作符取得的结果都是 undefined,但是实际上,技术上这两种情况完全不同。未赋值指的是变量已经声明但是未赋值,所以返回 undefined 指明未定义;未定义指的是变量未声明直接调用 typeof,所以这种情况我们期望返回 undeclared。
2. instanceof(返回布尔值)
在使用 typeof 运算符时采用引用类型存储值会出现一个问题,无论引用的是什么类型的对象,它都返回 “object”。ECMAScript 引入了另一个运算符 instanceof 来解决这个问题。instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。检测一个引用类型值和 Object 构造函数时,instanceof 始终返回 true。如果使用 instanceof 检测基本类型值,则返回 false,因为基本类型不是对象。
instanceof 用法示例:
示例一:
1
2var oStringObject = new String("hello world");
console.log(oStringObject instanceof String); // 输出 "true"示例二:
1
2
3
4// 判断 foo 是否是 Foo 类的实例
function Foo(){}
var foo = new Foo();
console.log(foo instanceof Foo) // true示例三:
1
2
3
4
5
6
7
8// 判断 foo 是否是 Foo 类的实例 , 并且是否是其父类型的实例
function Aoo(){}
function Foo(){}
Foo.prototype = new Aoo(); // JavaScript 原型继承
var foo = new Foo();
console.log(foo instanceof Foo) // true
console.log(foo instanceof Aoo) // true示例四:
1
2
3
4
5
6
7
8
9console.log(Object instanceof Object); //true
console.log(Function instanceof Function); // true
console.log(Number instanceof Number); // false
console.log(String instanceof String); // false
console.log(Function instanceof Object); // true
console.log(Foo instanceof Function); // true
console.log(Foo instanceof Foo); // false
剖析 instanceof 运算符定义
1 | function instance_of(L, R) {//L 表示左表达式,R 表示右表达式 |
instanceof 复杂用法(上述的最后三个例子)
Object instanceof Object
1
2
3
4
5
6
7
8
9
10
11
12// 为了方便表述,首先区分左侧表达式和右侧表达式
ObjectL = Object, ObjectR = Object;
// 下面根据规范逐步推演
O = ObjectR.prototype = Object.prototype
L = ObjectL.__proto__ = Function.prototype
// 第一次判断
O != L
// 循环查找 L 是否还有 __proto__
L = Function.prototype.__proto__ = Object.prototype
// 第二次判断
O == L
// 返回 trueFunction instanceof Function
1
2
3
4
5
6
7
8// 为了方便表述,首先区分左侧表达式和右侧表达式
FunctionL = Function, FunctionR = Function;
// 下面根据规范逐步推演
O = FunctionR.prototype = Function.prototype
L = FunctionL.__proto__ = Function.prototype
// 第一次判断
O == L
// 返回 trueFoo instanceof Foo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 为了方便表述,首先区分左侧表达式和右侧表达式
FooL = Foo, FooR = Foo;
// 下面根据规范逐步推演
O = FooR.prototype = Foo.prototype
L = FooL.__proto__ = Function.prototype
// 第一次判断
O != L
// 循环再次查找 L 是否还有 __proto__
L = Function.prototype.__proto__ = Object.prototype
// 第二次判断
O != L
// 再次循环查找 L 是否还有 __proto__
L = Object.prototype.__proto__ = null
// 第三次判断
L == null
// 返回 false
3. Object.prototype.toString
当 toString 方法被调用的时候,下面的步骤会被执行(ES5 的规范):
- If the this value is undefined, return “[object Undefined]” => 如果 this 值是 undefined,就返回 [object Undefined]
- If the this value is null, return “[object Null]” => 如果 this 值是 null,就返回 [object Null]
- Let O be the result of calling ToObject passing the this value as the argument => 让 O 成为 ToObject(this) 的结果
- Let class be the value of the [[Class]] internal property of O => 让 class 成为 O 的内部属性 [[Class]] 的值
- Return the String value that is the result of concatenating the three Strings “[object “, class, and “]” => 最后返回由 “[object “ 和 class 和 “]” 三个部分组成的字符串
通过规范,我们至少知道了调用 Object.prototype.toString 会返回一个由 “[object “ 和 class 和 “]” 组成的字符串,而 class 是要判断的对象的内部属性。正是因为这种特性,我们可以用 Object.prototype.toString 方法识别出更多类型。至于到底能识别多少种,emmmm,我告诉你 14 种你信吗?不信的话,那数数——
1 | console.log(Object.prototype.toString.call(1)); // [object Number] |
所以我数了数至少识别 14 种,哈哈哈哈~
之前也有针对常用的数据类型,写了一个比较完备的检测函数——
1 | /** |