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

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

csu 1446 Problem J Modified LCS (扩展欧几里得算法的简单应用)

这是一道扩展欧几里得算法的简单应用题,这题是在湖南多校训练赛中队友ac的一道题,在比赛之后请教了队友,然后自己把它a掉 这也是自己独自做扩展欧几里得算法的题目 题意:把题意转变下就变成了:求d1*x - d2*y = f2 - f1的解,很明显用exgcd来解 下面介绍一下exgcd的一些知识点:求ax + by = c的解 一、首先求ax + by = gcd(a,b)的解 这个

hdu2289(简单二分)

虽说是简单二分,但是我还是wa死了  题意:已知圆台的体积,求高度 首先要知道圆台体积怎么求:设上下底的半径分别为r1,r2,高为h,V = PI*(r1*r1+r1*r2+r2*r2)*h/3 然后以h进行二分 代码如下: #include<iostream>#include<algorithm>#include<cstring>#include<stack>#includ

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

usaco 1.3 Prime Cryptarithm(简单哈希表暴搜剪枝)

思路: 1. 用一个 hash[ ] 数组存放输入的数字,令 hash[ tmp ]=1 。 2. 一个自定义函数 check( ) ,检查各位是否为输入的数字。 3. 暴搜。第一行数从 100到999,第二行数从 10到99。 4. 剪枝。 代码: /*ID: who jayLANG: C++TASK: crypt1*/#include<stdio.h>bool h

uva 10387 Billiard(简单几何)

题意是一个球从矩形的中点出发,告诉你小球与矩形两条边的碰撞次数与小球回到原点的时间,求小球出发时的角度和小球的速度。 简单的几何问题,小球每与竖边碰撞一次,向右扩展一个相同的矩形;每与横边碰撞一次,向上扩展一个相同的矩形。 可以发现,扩展矩形的路径和在当前矩形中的每一段路径相同,当小球回到出发点时,一条直线的路径刚好经过最后一个扩展矩形的中心点。 最后扩展的路径和横边竖边恰好组成一个直

poj 1113 凸包+简单几何计算

题意: 给N个平面上的点,现在要在离点外L米处建城墙,使得城墙把所有点都包含进去且城墙的长度最短。 解析: 韬哥出的某次训练赛上A出的第一道计算几何,算是大水题吧。 用convexhull算法把凸包求出来,然后加加减减就A了。 计算见下图: 好久没玩画图了啊好开心。 代码: #include <iostream>#include <cstdio>#inclu

uva 10130 简单背包

题意: 背包和 代码: #include <iostream>#include <cstdio>#include <cstdlib>#include <algorithm>#include <cstring>#include <cmath>#include <stack>#include <vector>#include <queue>#include <map>

native和static native区别

本文基于Hello JNI  如有疑惑,请看之前几篇文章。 native 与 static native java中 public native String helloJni();public native static String helloJniStatic();1212 JNI中 JNIEXPORT jstring JNICALL Java_com_test_g

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件