js数据类型一共7种。
其中基本数据类型为
- Number
- String
- Boolean
- null
- undefined
- Symbol
基本数据类型是存储在栈内存中的。
- 引用数据类型
- Object Object 下还有很多细分的类型呐,如 Array、Function、Date、RegExp、Error 等。
引用数据类型是保存在堆内存中的,然后再栈内存中保存一个对堆内存中实际对象的引用。所以,JavaScript中对引用数据类型的操作都是操作对象的引用而不是实际的对象。
常见的类型判断有四种方式
- typeof
- instanceof
- constructor
- Object.prototype.toString
typeof 是一元操作符,放在其单个操作数的前面,操作数可以是任意类型。返回值为表示操作数类型的一个字符串
typeof undefined // "undefined"
typeof null // "object"
typeof true // "boolean"
typeof 1 // "number"
typeof "s" // "string"
typeof {} // "object"
typeof function a() {} // "function"
typeof [] //"object"
typeof new Date() // "object"
typeof new Error() // "object"
从上面的打印结果可以看出,typeof只能判断出6种类型。
从以上打印中,我们发现typeof null输出结果为"object",为什么会这样呢?
在 JS 的最初版本中,使用的是 32 位系统,为了性能考虑使用低位存储了变量的类型信息,000 开头代表是对象,然而 null 表示为全零,所以将它错误的判断为 object 。虽然现在的内部类型判断代码已经改变了,但是对于这个 Bug 却是一直流传下来。 由此可见,用typeof判断类型的话,对于引用对象的判断输出结果大部分都是"object",无法判断出具体的类型,对于这种情况,我们可以使用instanceof。
instanceof
object instanceof constructor
instanceof运算符可以检测constructor.prototype是不是在object的原型链上
instanceof的实现原理
function instanceof(L, R) { //L是表达式左边,R是表达式右边
var O = R.prototype;
L = L.__proto__;
while(true) {
if (L === null)
return false;
if (L === O)
return true;
L = L.__proto__;
}
}
construtor
每个对象实例都会有用__proto___关联的实例原型,这个实例原型有constructor属性指向他的构造函数。所以我们可以使用constructor来判断类型
function Child(){}
var a = new Child()
a.constructor === Child // true
但是construtor判断类型也有一些局限性:
还以上面的例子为入口:
function Child(){}
var a = new Child()
a.constructor === Object // false
a instanceof Object // true
- 由此可见,只要在一条原型链上,都可以用instanceof来判断,但constructor指向的是创建实例的那个方法。
- constructor 是可以用来判断基本数据类型的,但是instanceof不可以。
Object.prototype.toString()
var number = 1; // [object Number]
var string = '123'; // [object String]
var boolean = true; // [object Boolean]
var und = undefined; // [object Undefined]
var nul = null; // [object Null]
var sym = Symbol("sj"); // [object Symbol]
var obj = {a: 1} // [object Object]
var array = [1, 2, 3]; // [object Array]
var set = new Set(); // [object Set]
var map = new Map(); // [object Map]
var date = new Date(); // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g; // [object RegExp]
var func = function foo(){}; // [object Function]
- 在ES5规范中,每一种内置对象都定义了 [[Class]] 内部属性的值,用于内部区分对象的种类,而此规范只提供了Object.prototype.toString方法来访问此属性。
在ECMAScript 5中,Object.prototype.toString()被调用时,会进行如下步骤:
- 如果 this是undefined ,返回 [object Undefined]
- 如果 this是null , 返回 [object Null]
- 令 O 为以 this 作为参数调用 ToObject 的结果
- 令 class 为 O 的内部属性 [[Class]] 的值
- 返回三个字符串 "[object", class, 以及"]" 拼接而成的字符串