扒下JS的“底裤”之 typeof 运算符详解

简介: 扒下JS的“底裤”之 typeof 运算符详解

详解typeof

typeof语法

typeof是一个运算符

typeof 运算符后接操作数:

typeof operand
typeof(operand)
复制代码

参数operand是一个表示对象或原始值的表达式,其类型将被返回。


typeof返回值表

类型 结果
Undefined "undefined"
Null "object" (见下文)
Boolean "boolean"
Number "number"
BigInt(ECMAScript 2020 新增) "bigint"
String "string"
Symbol (ECMAScript 2015 新增) "symbol"
宿主对象(由 JS 环境提供) 取决于具体实现
Function 对象 (按照 ECMA-262 规范实现 [[Call]]) "function"
其他任何对象 "object"


检测示例

// 数值
typeof 37 === 'number';
typeof 3.14 === 'number';
typeof(42) === 'number';
typeof Math.LN2 === 'number';
typeof Infinity === 'number';
typeof NaN === 'number'; // 尽管它是 "Not-A-Number" (非数值) 的缩写
typeof Number(1) === 'number'; // Number 会尝试把参数解析成数值
typeof 42n === 'bigint';
// 字符串
typeof '' === 'string';
typeof 'bla' === 'string';
typeof `template literal` === 'string';
typeof '1' === 'string'; // 注意内容为数字的字符串仍是字符串
typeof (typeof 1) === 'string'; // typeof 总是返回一个字符串
typeof String(1) === 'string'; // String 将任意值转换为字符串,比 toString 更安全
// 布尔值
typeof true === 'boolean';
typeof false === 'boolean';
typeof Boolean(1) === 'boolean'; // Boolean() 会基于参数是真值还是虚值进行转换
typeof !!(1) === 'boolean'; // 两次调用 ! (逻辑非) 操作符相当于 Boolean()
// Symbols
typeof Symbol() === 'symbol';
typeof Symbol('foo') === 'symbol';
typeof Symbol.iterator === 'symbol';
// Undefined
typeof undefined === 'undefined';
typeof declaredButUndefinedVariable === 'undefined';
typeof undeclaredVariable === 'undefined';
// 对象
typeof {a: 1} === 'object';
// 使用 Array.isArray 或者 Object.prototype.toString.call
// 区分数组和普通对象
typeof [1, 2, 4] === 'object';
typeof new Date() === 'object';
typeof /regex/ === 'object'; // 历史结果请参阅正则表达式部分
// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。
typeof new Boolean(true) === 'object';
typeof new Number(1) === 'object';
typeof new String('abc') === 'object';
// 函数
typeof function() {} === 'function';
typeof class C {} === 'function'
typeof Math.sin === 'function';
// Null
// JavaScript 诞生以来便如此
typeof null === 'object';
// 除 Function 外的所有构造函数的类型都是 'object'
var str = new String('String');
var num = new Number(100);
typeof str; // 返回 'object'
typeof num; // 返回 'object'
var func = new Function();
typeof func; // 返回 'function'
复制代码


语法中的括号

// 括号有无将决定表达式的类型。
var iData = 99;
typeof iData + ' Wisen'; // 'number Wisen'  检测的变量是iDaya
typeof (iData + ' Wisen'); // 'string' 检测的变量是(iData + ' Wisen')
复制代码


正则表达式

对正则表达式字面量的类型判断在某些浏览器中不符合标准:

typeof /s/ === 'function'; // Chrome 1-12 , 不符合 ECMAScript 5.1
typeof /s/ === 'object'; // Firefox 5+ , 符合 ECMAScript 5.1
复制代码


为什么 typeof null === 'object';?

这里其实是一个JavaScript历史遗留问题,需要从JavaScript底层是如何存储数据的类型信息讲起。


简单来说就是

在 JS 的最初版本中使用的是 32 位系统,为了性能考虑使用低位存储变量的类型信息,000 开头代表是对象然而 null 表示为全零,所以将它错误的判断为 object

typeof原理: 不同的对象在底层都表示为二进制,在Javascript中二进制前(低)三位存储其类型信息。


000: 对象 010: 浮点数 100:字符串 110: 布尔 1: 整数

null:所有机器码均为0

Array: 1000100010001000
null:  0000000000000000
typeof []  // "object"
typeof null // "object"
复制代码

二进制中的“前”一般代表低位, 比如二进制00000011对应十进制数是3,它的前三位是011。这里null、Array的二进制前三位都是000 都被视为对象标签。


很多博主写的文章都是讲到这里就浅尝而止了,后面推荐的文章讲得更深。


推荐文章

typeof的原理?

“typeof null”的历史

JavaScript 的 typeof 原理小记


typeof也会报错

红宝书上讲过对未定义的变量使用typeof检测也会返回一个“undefined”。不会报错。

下面是详解


在 ECMAScript 2015 之前,typeof 总能保证对任何所给的操作数返回一个字符串。即便是没有声明的标识符,typeof 也能返回 'undefined'。使用 typeof 永远不会抛出错误。


但在加入了块级作用域的 let 和 const 之后,在其被声明之前对块中的 let 和 const 变量使用 typeof 会抛出一个 ReferenceError。块作用域变量在块的头部处于“暂存死区”,直至其被初始化,在这期间,访问变量将会引发错误。


红宝书p26对暂时性死区的概述


暂时性死区:在解析代码时,JavaScript 引擎也会注意出现在块后面的 let 声明,只不过在此之前不能以任何方式来引用未声明的变量。在 let 声明之前的执行瞬间被称为“暂时性死区”(temporal dead zone),在此阶段引用任何后面才声明的变量都会抛出 ReferenceError。


简单来说就是在使用let、const声明变量之前访问这个变量就会报错。


如果检查不存在的变量会抛出ReferenceError,请使用typeof nonExistentVar === 'undefined'。

typeof undeclaredVariable === 'undefined'; // 不会抛出错误
typeof newLetVariable; // ReferenceError
typeof newConstVariable; // ReferenceError
typeof newClass; // ReferenceError
let newLetVariable;
const newConstVariable = 'hello';
class newClass{};
复制代码


document.all类型是Undefined

对于document.all该特性已经从 Web 标准中删除,虽然一些浏览器目前仍然支持它,但也许会在未来的某个时间停止支持,请尽量不要使用该特性。

当前所有的浏览器都暴露了一个类型为 undefined 的非标准宿主对象 document.all

typeof document.all === 'undefined';
复制代码


尽管规范允许为非标准的外来对象自定义类型标签,但它要求这些类型标签与已有的不同。document.all 的类型标签为 'undefined' 的例子在 Web 领域中被归类为对原 ECMA JavaScript 标准的“故意侵犯”。


typeof为什么要区分object和function?

《JavaScript高级程序设计》:从技术角度讲,函数在ECMAScript中是对象,不是一种数据类型。然而,函数也确实有一些特殊的属性,因此通过typeof操作符来区分函数和其他对象是有必要的。


typeof wrapper 检测类型封装函数

function type(obj, fullClass) {
    // get toPrototypeString() of obj (handles all types)
    // Early JS environments return '[object Object]' for null, so it's best to directly check for it.
    // 早期JS环境 检测 null 返回'[object object]',所以最好直接检查它。
    if (fullClass) {
        return (obj === null) ? '[object Null]' : Object.prototype.toString.call(obj); // 输出[object,xxxx]
    }
    if (obj == null) { return (obj + '').toLowerCase(); } // implicit toString() conversion 隐式toString()转换
    var deepType = Object.prototype.toString.call(obj).slice(8,-1).toLowerCase();
    if (deepType === 'generatorfunction') { return 'function' }
    // Prevent overspecificity (for example, [object HTMLDivElement], etc).
    // 防止过度特异性(例如,[object HTMLDivElement]等)。
    // Account for functionish Regexp (Android <=2.3), functionish <object> element (Chrome <=57, Firefox <=52), etc. 
    // 解释功能化Regexp (Android <=2.3),功能化<对象>元素(Chrome <=57, Firefox <=52),等等。
    // String.prototype.match is universally supported. 
    // 普遍支持String.prototype.match。
    return deepType.match(/^(array|bigint|date|error|function|generator|regexp|symbol)$/) ? deepType :
       (typeof obj === 'object' || typeof obj === 'function') ? 'object' : typeof obj;
  }
  let user = {
    [Symbol.toStringTag]: "User"
  };
 console.log(type(user,false)); // object 有效的防止了过度特异性
 console.log(type(user,true)); // [object User]



目录
相关文章
|
1月前
|
JavaScript
js运算符
js运算符
21 5
|
1月前
|
JavaScript 前端开发
JavaScript 运算符全知道
JavaScript 运算符全知道
50 0
|
2月前
|
机器学习/深度学习 JavaScript 前端开发
JavaScript typeof, null, 和 undefined
JavaScript typeof, null, 和 undefined
53 4
|
2月前
|
JavaScript 前端开发
JavaScript 运算符
JavaScript 运算符
20 3
|
3月前
|
JavaScript 前端开发
JavaScript 中的 typeof 运算符
【8月更文挑战第29天】
24 1
|
3月前
|
JavaScript 前端开发 安全
深入理解JavaScript中的比较运算符
深入理解JavaScript中的比较运算符
|
3月前
|
前端开发 JavaScript 程序员
聊聊前端 JavaScript 的扩展运算符 “...“ 的使用场景
聊聊前端 JavaScript 的扩展运算符 “...“ 的使用场景
|
JavaScript 前端开发 算法
JavaScript基础(第一部分 -- 简介、注释、输入输出、变量、数据类型、运算符、流程控制)(六)
JavaScript基础(第一部分 -- 简介、注释、输入输出、变量、数据类型、运算符、流程控制)(六)
|
JavaScript 前端开发
JavaScript基础(第一部分 -- 简介、注释、输入输出、变量、数据类型、运算符、流程控制)(三)
JavaScript基础(第一部分 -- 简介、注释、输入输出、变量、数据类型、运算符、流程控制)(三)
|
JavaScript 前端开发
JavaScript基础(第一部分 -- 简介、注释、输入输出、变量、数据类型、运算符、流程控制)(五)
JavaScript基础(第一部分 -- 简介、注释、输入输出、变量、数据类型、运算符、流程控制)(五)