JS百题斩~ typeof 、instanceof 与 Object.prototype.toString 区别(简单易懂)

本文主要是介绍JS百题斩~ typeof 、instanceof 与 Object.prototype.toString 区别(简单易懂),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

首先,让我们先了解一下JavaScript的数据类型,分为两类:
基础类型:Undefined,Null,Boolean,Number,BigInt,String,Symbol
引用类型:Object,Array,Function

Symbol 是ES6中引入的一种原始数据类型,表示独一无二的值。BigInt(大整数)是 ES2020 引入的一种新的数据类型,用来解决 JavaScript中数字只能到 53 个二进制位。为了与 Number 类型区别,BigInt 类型的数据必须添加后缀n。 123为普通整数,123n为 BigInt。

typeof MDN docs

typeof是一个操作符而不是函数,用来检测给定变量的数据类型。typeof 总是返回一个字符串,用来说明变量的数据类型。
基本用法:

// 数值
typeof 37 === "number";
typeof NaN === "number";
typeof 42n === "bigint";// 字符串
typeof "1" === "string"; // 布尔值
typeof true === "boolean";// Symbols
typeof Symbol("foo") === "symbol";// Undefined
typeof undefined === "undefined";// Null
typeof null=== "object"; // JavaScript 诞生以来便如此// 对象
typeof { a: 1 } === "object";
typeof [1, 2, 4] === "object";
typeof new Date() === "object";
typeof /regex/ === "object";// 函数
typeof function () {} === "function";

上面可以看出,typeof 可以对除了null的基本数据类型做出准确的判断外,不能判断对象(如数组,正则等)具体是哪种类型,返回值都为“object”(除了Function会被识别出来),但是这些对象可以通过Object.prototype.toString.call() 查看内部属性。
在这里插入图片描述

typeof 操作符的优先级高于加法(+)等二进制操作符。因此,需要用括号来计算加法结果的类型。
// 括号有无将决定表达式的类型。
const num = 2;
typeof num + " foo"; // “number foo”
typeof (num+ " foo"); // “string”

typeof 原理

在JavaScript中,所有数值类型在底层都是以二进制形式表示的,由一个表示类型的标签和实际数据值表示的,前三位存储其类型信息。

二进制中的“前”一般代表低位, 比如二进制00000011对应十进制数是3,它的前三位是011。

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

因为对象的二进制表达前三位都是000,所以typeof无法区分。
由于 null 代表的是空指针(大多数平台下值为 0x00),因此null 的类型标签是 0,typeof null 也因此返回 “object”。

instanceof MDN docs

语法:object instanceof constructor
instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上(下篇讲原型链)。
通俗一些讲,instanceof 运算符用来检测一个对象是否为某一个构造函数的实例。注意,instanceof只能用于对象,不适用原始类型的值。

// 定义构造函数
function C() {}
function D() {}var o = new C();o instanceof C; // true,因为 Object.getPrototypeOf(o) === C.prototypeo instanceof D; // false,因为 D.prototype 不在 o 的原型链上o instanceof Object; // true,因为 Object.prototype.isPrototypeOf(o) 返回 true
C.prototype instanceof Object; // true,同上C.prototype = {};
var o2 = new C();o2 instanceof C; // trueo instanceof C; // false,C.prototype 指向了一个空对象,这个空对象不在 o 的原型链上。D.prototype = new C(); // 继承
var o3 = new D();
o3 instanceof D; // true
o3 instanceof C; // true 因为 C.prototype 现在在 o3 的原型链上

需要注意的是,如果表达式 obj instanceof Foo 返回 true,则并不意味着该表达式会永远返回 true,因为 Foo.prototype 属性的值有可能会改变,改变之后的值很有可能不存在于 obj 的原型链上,这时原表达式的值就会成为 false。另外一种情况下,原表达式的值也会改变,就是改变对象 obj 的原型链的情况,虽然在目前的 ES 规范中,我们只能读取对象的原型而不能改变它,但借助于非标准的 proto 伪属性,是可以实现的。比如执行 obj.proto = {} 之后,obj instanceof Foo 就会返回 false 了。

关于 instanceof 的实现原理,参考下面代码:

function myInstanceof(left, right) {// 这里先用 typeof 判断基础数据类型,如果是,直接返回falseif (typeof left !== 'object' || left === null) return false;// getPrototypeOf是Object对象自带的API,能够拿到left参数的原型对象let proto = Object.getPrototypeOf(left);while(true) {if (proto === null) return false;if (proto === right.prototype) return true; // 找到相同原型对象,返回trueproto = Object.getPrototypeOf(left);}
}

顺着原型链去找,直到找到相同的原型对象。

区别

typeof 与 instanceof 都是判断数据类型的方法,区别如下:

  • typeof 返回一个字符串,是变量的基本类型,instanceof 返回的是一个Boolean值;
  • instanceof 可以准确地判断复杂引用数据类型,但不能判断基础数据类型;
  • typeof 虽然可以判断基础数据类型( null 除外),但是引用数据类型中,除了Function类型以外,其他的也无法判断;

上述两种检测方法都有弊端,不能满足所有场景的需求,如果需要通用数据类型检测方法,可以使用Object.prototype.toString。

Object.prototype.toString.call() 推荐! MDN docs

这是对象的一个原生原型扩展函数,用来更精确的区分数据类型。
对于 Object.prototype.toString() 方法,调用该方法,返回统一的格式"[object xxxx]"的字符串。如果对象的 toString() 方法未被重写,就会返回如上面形式的字符串。
但是,大多数对象,toString() 方法都是重写了的,这时,需要用 call() 方法来调用。

Object.prototype.toString({});  // "[object Object]"
Object.prototype.toString.call({});  // "[object Object]"
Object.prototype.toString.call(1);  // "[object Number]"
Object.prototype.toString.call('1');  // "[object String]"
Object.prototype.toString.call(true);  // "[object Boolean]"
Object.prototype.toString.call(function(){});  // "[object Function]"
Object.prototype.toString.call(null);  // "[object Null]"
Object.prototype.toString.call(undefined);  // "[object Undefined]"
Object.prototype.toString.call(/123/g);  // "[object RegExp]"
Object.prototype.toString.call(new Date());  // "[object Date]"
Object.prototype.toString.call([]);  // "[object Array]"
Object.prototype.toString.call(document);  // "[object HTMLDocument]"
Object.prototype.toString.call(window);  // "[object Window]"

下一篇(待完成): JS百题斩~ 原型 与 原型链

这篇关于JS百题斩~ typeof 、instanceof 与 Object.prototype.toString 区别(简单易懂)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1031181

相关文章

MySQL中VARCHAR和TEXT的区别小结

《MySQL中VARCHAR和TEXT的区别小结》MySQL中VARCHAR和TEXT用于存储字符串,VARCHAR可变长度存储在行内,适合短文本;TEXT存储在溢出页,适合大文本,下面就来具体的了解... 目录一、VARCHAR 和 TEXT 基本介绍1. VARCHAR2. TEXT二、VARCHAR

JS纯前端实现浏览器语音播报、朗读功能的完整代码

《JS纯前端实现浏览器语音播报、朗读功能的完整代码》在现代互联网的发展中,语音技术正逐渐成为改变用户体验的重要一环,下面:本文主要介绍JS纯前端实现浏览器语音播报、朗读功能的相关资料,文中通过代码... 目录一、朗读单条文本:① 语音自选参数,按钮控制语音:② 效果图:二、朗读多条文本:① 语音有默认值:②

在Node.js中使用.env文件管理环境变量的全过程

《在Node.js中使用.env文件管理环境变量的全过程》Node.js应用程序通常依赖于环境变量来管理敏感信息或配置设置,.env文件已经成为一种流行的本地管理这些变量的方法,本文将探讨.env文件... 目录引言为什么使php用 .env 文件 ?如何在 Node.js 中使用 .env 文件最佳实践引

使用Node.js和PostgreSQL构建数据库应用

《使用Node.js和PostgreSQL构建数据库应用》PostgreSQL是一个功能强大的开源关系型数据库,而Node.js是构建高效网络应用的理想平台,结合这两个技术,我们可以创建出色的数据驱动... 目录初始化项目与安装依赖建立数据库连接执行CRUD操作查询数据插入数据更新数据删除数据完整示例与最佳

Python实现简单封装网络请求的示例详解

《Python实现简单封装网络请求的示例详解》这篇文章主要为大家详细介绍了Python实现简单封装网络请求的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录安装依赖核心功能说明1. 类与方法概览2.NetHelper类初始化参数3.ApiResponse类属性与方法使用实

python中getsizeof和asizeof的区别小结

《python中getsizeof和asizeof的区别小结》本文详细的介绍了getsizeof和asizeof的区别,这两个函数都用于获取对象的内存占用大小,它们来自不同的库,下面就来详细的介绍一下... 目录sys.getsizeof (python 内置)pympler.asizeof.asizeof

Vue和React受控组件的区别小结

《Vue和React受控组件的区别小结》本文主要介绍了Vue和React受控组件的区别小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学... 目录背景React 的实现vue3 的实现写法一:直接修改事件参数写法二:通过ref引用 DOMVu

Three.js构建一个 3D 商品展示空间完整实战项目

《Three.js构建一个3D商品展示空间完整实战项目》Three.js是一个强大的JavaScript库,专用于在Web浏览器中创建3D图形,:本文主要介绍Three.js构建一个3D商品展... 目录引言项目核心技术1. 项目架构与资源组织2. 多模型切换、交互热点绑定3. 移动端适配与帧率优化4. 可

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Go之errors.New和fmt.Errorf 的区别小结

《Go之errors.New和fmt.Errorf的区别小结》本文主要介绍了Go之errors.New和fmt.Errorf的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考... 目录error的基本用法1. 获取错误信息2. 在条件判断中使用基本区别1.函数签名2.使用场景详细对