js类型判断

185 阅读3分钟

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()被调用时,会进行如下步骤:

    1. 如果 this是undefined ,返回 [object Undefined]
    2. 如果 this是null , 返回 [object Null]
    3. 令 O 为以 this 作为参数调用 ToObject 的结果
    4. 令 class 为 O 的内部属性 [[Class]] 的值
    5. 返回三个字符串 "[object", class, 以及"]" 拼接而成的字符串