您好, 欢迎来到 !    登录 | 注册 | | 设为首页 | 收藏本站

typeof

typeof 操作符返回字符串,表示未经计算的操作数的类型。(MDN)

typeof 可以用来检测值的类型。

在 ES6 之前,typeof 在浏览器的表现是这样的:

typeof ; // :"number"

typeof '嘎?'; // :"string"

typeof true; // :"boolean"

typeof undefined; // :"undefined"

var fn1 = function() {};
function fn2() {};
typeof fn1; // :"function"
typeof fn2; // :"function"

typeof null; // :"object"

typeof []; // :"object";
typeof ['9', '9', '6']; // :"object";

typeof {}; // :"object"

这是历史遗留问题,JavaScript 从出现开始都是这个表现。

typeof null; // :"object"

原因是 null 表示为空指针,其内部表示类型的和对象相同,所以会被设别为 object

有提案表示想要修复这个问题,使表现如下:

typeof null; // :"null"

但这个提案被拒绝了。

数组的本质是个对象,从数组的原型上观察就可以发现。

同时可以通过 instanceof 检测数组的原型链上是否有 Object。

Array instanceof Object; // :true

事实上 typeof 只对字面量敏感。

var num = ;

typeof num; // :"number"

如果采用构造的形式得到值:

var num = new Number();

typeof num; // :"object"

所以除了 Function,构造出来的值,使用 typeof 检测类型都会返回 object

var fn = new Function('console.log("我是特例!")');

typeof fn; // :"function"

使用 Object.prototype.toString.call,可以更精准的检测类型。

Object.prototype.toString.call(); // : [object Number]
Object.prototype.toString.call(false); // : [object Boolean]
Object.prototype.toString.call(null); // : [object Null]
Object.prototype.toString.call([]); // : [object Array]
Object.prototype.toString.call({}); // : [object Object]

通过观察结果可以看到,使用这个方式可以区别出数组、对象、null这些 typeof 无法区分的类型。

可是为什么要这样用呢?不能直接值的 toString 吗?

这涉及到了原型的问题,例如 Number

var number = ;

console.log(number.__proto__.toString);

number 变量的 toString 其实就是 Numberprototype 下的 toString

var number = ;

console.log(number.__proto__.toString === Number.prototype.toString);

从这就可以看出进行 number.toString() 操作,的就不是 Object.prototype.toString 了。

这两个 toString 的不同,Number.prototype.toString 做的事情其实就是根据一些规则,将值转成字符串,而 Object.prototype.toString 是将对象的类型进行组合。

也就是说大部分数据类型的原始对象都提供了新的 toString ,也就无法到 Object.prototype.toString,所以要用这种方式。

那为什么 Object.prototype.toString 会可以精准判断出值的类型呢?

这是因为每个值都有对应的类型,在标准中为 [[class]]

ES6 中,则是使用Symbol.toStringTag作为。

Object.prototype.toString 在的时候,就会访问这个,并返回 [object ]

var obj = {
  [Symbol.toStringTag]: '996',
};

Object.prototype.toString.call(obj); // :"[object 996]"

所有内置的类型都具有这个,所以使用 Object.prototype.toString.call(值) 的方式可以更精准的到值的类型。

一些旧的数据类型的基础对象为了兼容性,可能访问不到 Symbol.toStringTag 接口,但是其他许多内置对象可以,例如JSONMathBigInt等:

JSON[Symbol.toStringTag]; // :"JSON"
Math[Symbol.toStringTag]; // :"Math"
BigInt.prototype[Symbol.toStringTag]; // :"BigInt"

typeof 经常被用来检测基础类型,但是不够准确,无法区分数组、对象、null,更精准的检测应考虑使用 Object.prototype.toString


联系我
置顶