instanceof和typeof的区别

instanceof和typeof的区别

在看他们的区别之前我觉得我们需要先了解两者

instanceof

来自官方的定义:

instanceof 运算符 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上

它是可以检测到每个实例对象是否出现在构造函数的原型对象prototype链上

所以在了解此知识前我们需要先了解原型链知识

在这篇文章中我们就不过多介绍了

所以我们先看关于instanceof的代码例子

js 复制代码
function Car(make, model, year) {
  this.make = make;
  this.model = model;
  this.year = year;
}
const auto = new Car('Honda', 'Accord', 1998);

console.log(auto instanceof Car);
// 输出: true

console.log(auto instanceof Object);
// 输出: true

因为auto的原型链中是

js 复制代码
auto
↓
Car.prototype
↓
Object.prototype
↓
null

CarObject的原型对象``prototype在auto的原型链中所以结果为true

但是呢其实instanceof的结果也不是一成不变的

我们看以下示例

js 复制代码
//定义两个函数
function C() {}
function D() {}

const o = new C();    //o-->C.prototype-->Object.prototype-->null

o instanceof C;     // true

o instanceof D;      // false  o的原型链中没有D.prototype

o instanceof Object;   // true

C.prototype instanceof Object; // true           C.prototype的原型链为C.prototype-->Object.prototype-->null  
//因为Object的prototype在C.prototype的原型链中  所以结果为true

C.prototype = {};   //在这里重写了C.prototype 赋予了他新的一个对象 
//   原型链变为   C的新prototype--> Object.prototype-->null 
const o2 = new C();  //原型链为   o2-->C的新prototype--> Object.prototype-->null 

o2 instanceof C; // true   综上所述  为true

o instanceof C;  //false   因为此时C的原型不在o的原型链中  因为o的原型链未被改变  其原型链中的元素还是一样  只是其中原本为C的prototype不再是  C的prtotype  但是o的原型链指向不变  还是原来的内存地址上的对象 所以在instanceof运算符执行时发现C的原型不在原型链中

D.prototype = new C();
const o3 = new D();   //其原型链为  o3 ---> D.prototype ---> new C() ---> C.prototype ---> Object.prototype ---> null
o3 instanceof D; // true   
o3 instanceof C; // true 

其实 instanceof 运算符就是检测目标对象的原型链上是否有某个构造函数的prototype 有就返回true 否则 false

但是构造函数的prototype不是一成不变的 所以 instanceof的值也不是一成不变的

还有也要注意目标变量是否为对象

js 复制代码
var simpleStr = "This is a simple string";
var myString = new String();
var newStr = new String("String created with constructor");


simpleStr instanceof String; // 返回 false,非对象实例,因此返回 false   
myString instanceof String; // 返回 true
newStr instanceof String; // 返回 true

在上面simpleStr只是一个基本类型变量不是一个实例对象

让我们来手写一个instanceof

这也是面试经常考察的点

其实中心思想就是按着实例对象的proto在原型链上一直寻找构造函数的prototype在不在上面

js 复制代码
function Instanceof(instance, construction) {
  let instanceval = instance.__proto__;
  let Prototype = construction.prototype;
  while (true) {
    if (instanceval === null) return false;
    if (instanceval === Prototype) return true;
    instanceval = instanceval.__proto__;
  }
}
console.log(Instanceof({},Object));  //输出:true

typeof

typeof 运算符返回一个字符串,表示操作数的类型。

js 在底层存储变量的时候,会在变量的机器码的低位1-3位存储其类型信息

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

null:是 000 所以才判断为对象

js 复制代码
console.log(typeof 42);
// 输出 "number"
console.log(typeof 'blubber');
// 输出 "string"
console.log(typeof true);
// 输出 "boolean"
console.log(typeof undeclaredVariable);
// 输出 "undefined"

我们先看一下能够返回的值的列表

类型 结果
Undefined "undefined"
Null "object"原因
Boolean "boolean"
Number "number"
BigInt "bigint"
String "string"
Symbol "symbol"
Function(在 ECMA-262 中实现 [[Call]];classes也是函数) "function"
其他任何对象 "object"

我们要注意null返回的也是object

我们再看MDN上的例子

typeof 操作符的优先级高于加法(+)等二进制操作符

js 复制代码
// 数值
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 Number("shoe") === "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";

// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。  new出来的都是对象
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";

你在上面也发现了typeof很难准确判断引用类型 因为都是返回object 除了函数 但是对于基础类型数据能够很好的判断

两者区别

根据上面两个介绍我相信大家都有了很好的一个了解,主要总结两者以下的特点

  • typeof 会返回一个运算数的基本类型,instanceof 返回的是布尔值
  • instanceof能够很好的判断引用数据的类型,但是对于基础类型数据无法判断
  • typeof能够很好的判断基础数据类型,但是无法很好的判断引用类型,因为都会返回object
  • 所以两者可以说是互补,在合适的地方使用
相关推荐
一颗花生米。2 小时前
深入理解JavaScript 的原型继承
java·开发语言·javascript·原型模式
学习使我快乐012 小时前
JS进阶 3——深入面向对象、原型
开发语言·前端·javascript
bobostudio19952 小时前
TypeScript 设计模式之【策略模式】
前端·javascript·设计模式·typescript·策略模式
勿语&3 小时前
Element-UI Plus 暗黑主题切换及自定义主题色
开发语言·javascript·ui
黄尚圈圈3 小时前
Vue 中引入 ECharts 的详细步骤与示例
前端·vue.js·echarts
浮华似水4 小时前
简洁之道 - React Hook Form
前端
正小安6 小时前
如何在微信小程序中实现分包加载和预下载
前端·微信小程序·小程序
_.Switch7 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光7 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   7 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发