每天一道JS手写题💪「Day1数据类型判断+手写instanceof」

数据类型判断

typeof

typeof 可以区分基础数据类型,而对所有的引用数据类型都会返回 object, 对所有的类都会返回 function(在 ECMA-262 中实现 [[Call]];classes也是函数)。

js 复制代码
typeof "Ken"                  // 返回 "string"
typeof 3.14                   // 返回 "number"
typeof false                  // 返回 "boolean"
typeof function () {}         // 返回 "function"
typeof undefined              // 返回 "undefined"
typeof [1,2,3,4]              // 返回 "object"
typeof {name:'Ken', age:18}   // 返回 "object"
typeof new Date()             // 返回 "object"
typeof null                   // 返回 "object"
typeof Object                 // 返回 "function"
typeof Number                 // 返回 "function"

instanceof

instanceof 运算符 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。基础数据类型、undefined、null没有构造函数,都无法使用这一方法。

js 复制代码
123 instanceof Number                // 返回 false
new Number(123) instanceof Number    // 返回 true

'123' instanceof String              // 输出 false
new String('123') instanceof String  // 返回 true

([]) instanceof Array                // 返回 true
({}) instanceof Object               // 返回 true
(function(){}) instanceof Function   // 返回 true

constructor

Object 实例的 constructor 数据属性返回一个引用,指向创建该实例对象的构造函数。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。

constructor能判断基本数据类型string、number、boolean和对象类型(array、function等等),但是它不能判断 undefined 和 null,试图从 undefined 和 null 上读属性是会报错的。

js 复制代码
const o1 = {};
o1.constructor === Object; // true

const o2 = new Object();
o2.constructor === Object; // true

const a1 = [];
a1.constructor === Array; // true

const a2 = new Array();
a2.constructor === Array; // true

const n = 3;
n.constructor === Number; // true

Object.prototype.toString.call()

js 复制代码
function typeOf(obj) {
    // Object.prototype.toString() 的输出是 [Object object] 这种格式,这里通过 slice 做了裁剪
    return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();
}

typeOf([])        //返回 'array'
typeOf({})        //返回 'object'
typeOf(new Date)  //返回 'date'

关于这种方法 mdn 文档中有提及 Object.prototype.toString()

以这种方式使用 toString() 是不可靠的;对象可以通过定义 Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为,从而导致意想不到的结果。

但实际开发中我们大多不会去修改 Symbol.toStringTag 属性的值,故而这种方法已经够用了。

为什么Object.prototype.toString.call()可以准确判断数据类型呢?

简单的说就是官方的定义,Object.prototype上的 toString 方法,它就是干这个的。

但要注意的是每个数据类,他们都重写了 toString() 方法,例如我们熟悉的打印数组和对象。所以判断类型必须使用 Object.prototype 上的 toString 方法,而不是当前数据本身的 toString

为什么最后要加 call() 呢?

因为 Object.prototype.toString() 返回的是调用者的类型。不论你 toString() 本身的入参写的是什么,在Object.prototype.toString() 中,他的调用者永远都是 Object.prototype;所以,在不加 call() 情况下,我们的出来的结果永远都是 [object Object]

这里的 call() 方法, 是为了改变 Object.prototype.toString 这个函数中的 this 指向。让 Object.prototype.toString 这个方法的 this 指向我们所传入的数据。

对比

typeof instanceof constructor Object.prototype.toString
可用性 可以判断基本数据类型 instanceof 可以用于判断具有构造函数的引用数据类型 constructor能判断基本数据类型string、number、boolean和对象类型 Object.prototype.toString.call() 方法是判断类型的最准确的方法
局限性 对所有的引用类型都会返回object 无法判断不具有构造函数的基本数据类型、undefined 和 null 不能判断undefined和null 对象可以通过定义Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为

写到这里我还有一个小疑惑,为什么 instanceof 无法判断基本数据类型,但是 constructor 可以呢?原来JavaScript 在读取基本数据类型的 constructor 属性时,会隐式地将原始值封装成相应的包装对象,这种行为是 JavaScript 语言规范中定义的, 最后其实你访问到的是这个临时的包装对象上的属性。

实现一个 instanceof

在动手实现 instanceof 之前,我们要先知道它的功能是如何实现的:

  1. instancof 有两个参数,一个待判断的对象obj和一个构造函数constructor
  2. 如果 instancof 右侧的参数不是一个函数,它会报错 Right-hand side of 'instanceof' is not an object .
  3. 它检查obj是否为一个对象或函数,如果不是,则返回false,因为基础数据类型不具有构造函数。
  4. 获取obj的原型,并沿着原型链向上查找,直到找到与constructor.prototype相同的原型或者到达原型链的顶端。如果找到了相同的原型,则返回true,否则返回false

代码:

js 复制代码
function myInstanceOf(obj, constructor) {
    if (typeof constructor !== 'function') {
        throw new TypeError('Right-hand side of \'instanceof\' is not an object');
    }
    if (obj === null || typeof obj !== 'object' && typeof obj !== 'function') {
        return false;
    }
    let proto = Object.getPrototypeOf(obj);
    while (proto) {
        if (proto === constructor.prototype) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }
    return false;
}
相关推荐
C澒几秒前
Vue 项目渐进式迁移 React:组件库接入与跨框架协同技术方案
前端·vue.js·react.js·架构·系统架构
xiaoxue..14 分钟前
合并两个升序链表 与 合并k个升序链表
java·javascript·数据结构·链表·面试
清山博客34 分钟前
OpenCV 人脸识别和比对工具
前端·webpack·node.js
要加油哦~37 分钟前
AI | 实践教程 - ScreenCoder | 多agents前端代码生成
前端·javascript·人工智能
程序员Sunday40 分钟前
说点不一样的。GPT-5.3 与 Claude Opus 4.6 同时炸场,前端变天了?
前端·gpt·状态模式
yq1982043011561 小时前
静思书屋:基于Java Web技术栈构建高性能图书信息平台实践
java·开发语言·前端
一个public的class1 小时前
你在浏览器输入一个网址,到底发生了什么?
java·开发语言·javascript
aPurpleBerry1 小时前
monorepo (Monolithic Repository) pnpm rush
前端
青茶3601 小时前
php怎么实现订单接口状态轮询请求
前端·javascript·php
火车叼位1 小时前
脚本伪装:让 Python 与 Node.js 像原生 Shell 命令一样运行
运维·javascript·python