本文主要是介绍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 区别(简单易懂)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!