当前位置: 首页 > news >正文

Javascript高级—如何实现一个类型判断函数?

实现一个类型判断函数

  1. 判断null
  2. 判断基础类型
  3. 使用Object.prototype.toString.call(target)来判断引用类型

[!NOTE]
注意: 一定是使用call来调用,不然是判断的Object.prototype的类型

之所以要先判断是否为基本类型是因为:虽然Object.prototype.toString.call()能判断出某值是:number/string/boolean,但是其实在包装的时候是把他们先转成了对象然后再判断类型的。 但是JS中包装类型和原始类型还是有差别的,因为对一个包装类型来说,typeof的值是object

/*** 类型判断*/
function getType(target) {//先处理最特殊的Nullif(target === null) {return 'null';}//判断是不是基础类型const typeOfT = typeof targetif(typeOfT !== 'object') {return typeOfT;}//肯定是引用类型了const template = {"[object Object]": "object","[object Array]" : "array","[object Function]": "function",// 一些包装类型"[object String]": "object - string","[object Number]": "object - number","[object Boolean]": "object - boolean"};const typeStr = Object.prototype.toString.call(target);return template[typeStr];
}

升级版本

// typeof可以检测基本数据类型
// Undefined, Null, Boolean, Number, String, Objec
// undefined, object, boolean, number, string, object// 以下是11种:
var number = 1;          // [object Number]
var string = '123';      // [object String]
var boolean = true;      // [object Boolean]
var und = undefined;     // [object Undefined]
var nul = null;          // [object Null]
var obj = {a: 1}         // [object Object]
var array = [1, 2, 3];   // [object Array]
var date = new Date();   // [object Date]
var error = new Error(); // [object Error]
var reg = /a/g;          // [object RegExp]
var func = function a(){}; // [object Function]function checkType() {for (var i = 0; i < arguments.length; i++) {console.log(Object.prototype.toString.call(arguments[i]))}
}checkType(number, string, boolean, und, nul, obj, array, date, error, reg, func)console.log(Object.prototype.toString.call(Math)); // [object Math]
console.log(Object.prototype.toString.call(JSON)); // [object JSON]function a() {console.log(Object.prototype.toString.call(arguments)); // [object Arguments]
}a();// TODO:Object.toString()的理解?
/*1. 如果 this 值是 undefined,就返回 [object Undefined]2. 如果 this 的值是 null,就返回 [object Null]3. 让 O 成为 ToObject(this) 的结果4. 让 class 成为 O 的内部属性 [[Class]] 的值5. 最后返回由 "[object " 和 class 和 "]" 三个部分组成的字符串*/// TODO:封装一个通用的type API?
// v1: 基础版本
var class2type = {};'Undefined Null String Number Boolean Object Function Array Date RegExp Error'.split(' ').map(function (item) {// 开始建立映射关系class2type[`[object ${item}]`] = item.toLowerCase();})function type(obj) {return typeof obj === 'object' || typeof obj === 'function'? class2type[Object.prototype.toString.call(obj)] || 'object': typeof obj;
}// v2:在 IE6 中,null 和 undefined 会被 Object.prototype.toString 识别成 [object Object]!
// TODO: 解决IE6下的null和undefined 会被识别为[object Object]?
var class2type = {};
'Undefined Null String Number Boolean Object Function Array Date RegExp Error'.split(' ').map(function (item) {class2type[`[object ${item}]`] = item.toLowerCase();
})/*** 查看type的基础类型* @param obj* @return {string|*}*/
function type(obj) {// 开始解决ie下的兼容问题if (obj == null) {return obj + '';}return typeof obj === 'object' || obj === 'function'//  ES6 新增的 Symbol、Map、Set 等类型,它们并不在 class2type 列表中,所以使用 type 函数,返回的结果会是 object? class2type[Object.prototype.toString.call(obj)] || 'object': typeof obj;
}/*** 查看obj是否为函数累类型* @param obj* @return {boolean}*/
function isFunction(obj) {return type(obj) === 'function';
}/*** 注意这里的isArray是一个函数,并不是一个函数执行的结果* @type {((arg: any) => arg is Array<any>) | (function(*=): boolean)}*/
var isArray = Array.isArray || function (obj) {return type(obj) === 'array';
}// TODO: plainObject, 就是该对象是通过 "{}" 或 "new Object" 创建的,该对象含有零个或者多个键值对?
// 存放toString的映射结果
var class2type = {};
// Object.prototype.toString
var toString = class2type.toString();
// Object.prototype.hasOwnProperty
var hasOwn = class2type.hasOwnProperty;function isPlainObject(obj) {// 排除掉宿主对象 eg: toString.call(window) === '[objct window]'if (!obj || toString.call(obj) !== '[object Object]') {return false;}/*** Object.getPrototypeOf() 方法返回指定对象的原型(即, 内部[[Prototype]]属性的值),如果没有继承属性,则返回 null 。* eg: obj.__proto__ === Object.protptype* @type {any}*/var proto = Object.getPrototypeOf(obj);// 如果没有原型对象的话,eg:Object.create(null), 就是纯对象if (!proto) {return true;}// 通过new Object方式创建的对象// 判断 proto 是否有 constructor 属性,如果有就让 Ctor 的值为 proto.constructorvar Constructor = hasOwn.call(proto, 'constructor') && proto.constructor;// 判断Constructor是不是Object的构造函数return typeof Constructor === 'function' && hasOwn.toString.call(Constructor) === hasOwn.toString.call(Object);
}// TODO: EmptyObject如何判断?
function isEmptyObject(obj) {var name;// 看一下当前的这个obj对象有没有属性,如果有的话就返回falsefor (name in obj) {// 遍历的不仅仅是obj自身的属性,而且也遍历了obj原型上的属性return false;}return true;
}
// test
console.log(isEmptyObject({})); // true
console.log(isEmptyObject([])); // true
console.log(isEmptyObject(null)); // true
console.log(isEmptyObject(undefined)); // true
console.log(isEmptyObject(1)); // true
console.log(isEmptyObject('')); // true
console.log(isEmptyObject(true)); // true// TODO: 判断是否为window对象?
// window对象的window属性指向其本身
function isWindow(obj) {return obj != null && obj == obj.window;
}// TODO: 判断是否为document对象?
function isDocument(obj) {return obj != null && obj.nodeType == obj.DOCUMENT_NODE;
}// TODO: 判断是不是DOM元素
function isDOMElement(obj) {// 这里需要强制把返回的结果转换为bool类型,eg:obj = undefined,!!undefined=r\truereturn !!(obj && obj.nodeType === 1);
}// TODO: isArrayLike如何实现?(可以判断数组和伪数组类型)
function isArrayLike(obj) {// 1. 先看obj有没有length属性var length = !!obj && ('length' in obj) && obj.length;var typeRes = type(obj);// 2. 排除掉函数和window对象, window也是有length属性的if (typeRes === 'function' || isWindow(obj)) {return false;}// 3. 开始处理结果return typeRes === 'array'                  // 1. 是数组类型|| length === 0                     // 2. 长度为0(函数中的arguments参数)|| typeof length === 'number'&& length > 0&& (length - 1) in obj;             // 3. length 属性是大于 0 的数字类型,并且obj[length - 1]必须存在(符合条件的类数组对象是一定存在最后一个元素的)}// underscore 如何实现的?
function isArrayLike(collection) {var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;var length = getLength(collection);return typeof length === 'number' && length >= 0 && length <= MAX_ARRAY_INDEX;
}

相关文章:

Javascript高级—如何实现一个类型判断函数?

实现一个类型判断函数 判断null判断基础类型使用Object.prototype.toString.call(target)来判断引用类型 [!NOTE] 注意&#xff1a; 一定是使用call来调用&#xff0c;不然是判断的Object.prototype的类型 之所以要先判断是否为基本类型是因为&#xff1a;虽然Object.prototyp…...

asitop macOS 终端 性能监控

macOS 终端 性能监控 安装 pip python3 -m ensurepip# pip3 --version pip 21.2.4安装 asitop pip3 install asitop运行 sudo asitop参考 asitopgithub asitopHow to Install pip on Mac...

Unity学习笔记(4):人物和基本组件

文章目录 前言开发环境新增角色添加组件RigidBody 2D全局项目设置Edit 给地图添加碰撞体 总结 前言 今天不加班&#xff0c;有空闲时间。争取一天学一课&#xff0c;养成习惯 开发环境 Unity 6windows 11vs studio 2022Unity2022.2 最新教程《勇士传说》入门到进阶&#xff…...

【深圳大学/大学物理实验2】弗兰克-赫兹实验预习题参考

一、单选题 共 13 小题 共 78 分 1. (6分)第一栅极电压UG1、第二栅极电压UG2和减速电压UP的作用分别是&#xff08; &#xff09; 学生答案&#xff1a;C √ A. 使电子加速&#xff0c;消除阴极电子散射&#xff0c;使电子减速 B. 产生并加速电子&#xff0c;使电子加速&…...

vue2.7.14 + vant + vue cli脚手架转vite启动运行问题记录

文章目录 前言方案一&#xff08;借用插件转换&#xff09;启动命令&#xff0c;转换方案一转换遇到的问题 方案二&#xff08;手动调整&#xff09;方案两者对比小结 前言 vue cli 脚手架转成vite启动 简单说说这个项目的一些底层基本结构哈&#xff0c;以及写这篇博客的目的…...

Java基础-内部类与异常处理

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 一、Java 内部类 什么是内部类&#xff1f; 使用内部类的优点 访问局部变量的限制 内部类和继承 内部…...

vue2或vue3的name属性有什么作用?

在 Vue.js&#xff08;无论是 Vue 2 还是 Vue 3&#xff09;中&#xff0c;组件的 name 属性有几个重要的用途。虽然它不是必须的&#xff0c;但在某些情况下非常有用。以下是 name 属性的一些主要作用&#xff1a; 1. 调试工具 Vue Devtools 和其他调试工具会使用组件的 nam…...

【FOC进阶日记】实战篇③ 电机关键数据采集方法

作者 | 量子君 微信公众号 | 极客工作室 【FOC进阶日记】专栏目录 第一章 实战篇① FOC与SVPWM详解 第二章 实战篇② 自发电控制算法 第三章 实战篇③ 电机关键数据采集方法 文章目录 前言一、M法(从路程入手):二、T法(从时间入手)三、M/T测速法:四、实现过程:总结前言…...

XSS安全基础

欢迎关注公众号【测试开发备忘录】&#xff0c;交流学习经验 XSS 类型&#xff1a; 反射型XSS&#xff1a;简单的把用户输入的数据“反射”给浏览器&#xff0c;将恶意链接嵌入&#xff0c;非持久&#xff1b; 存储型XSS&#xff1a;把用户输入的数据“存储”在服务端&#xf…...

【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】试卷(3)

前言 大家好吖&#xff0c;欢迎来到 YY 滴计算机网络 系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过C的老铁 本博客主要内容&#xff0c;收纳了一部门基本的计算机网络题目&#xff0c;供yy应对期中考试复习。大家可以参考 本章是去答案版本。带答案的版本在下…...

516.最长回文子序列

刷算法题&#xff1a; 第一遍&#xff1a;1.看5分钟&#xff0c;没思路看题解 2.通过题解改进自己的解法&#xff0c;并且要写每行的注释以及自己的思路。 3.思考自己做到了题解的哪一步&#xff0c;下次怎么才能做对(总结方法) 4.整理到自己的自媒体平台。 5.再刷重复的类…...

leetcode hot100【LeetCode 114.二叉树展开为链表】java实现

LeetCode 114.二叉树展开为链表 题目描述 给你二叉树的根结点 root &#xff0c;请你将它展开为一个单链表&#xff1a; 展开后的单链表应该同样使用 TreeNode &#xff0c;其中 right 子指针指向链表中下一个结点&#xff0c;而左子指针始终为 null 。 展开后的单链表应该与…...

SpringMVC学习记录(二)之接收数据

SpringMVC学习记录&#xff08;二&#xff09;之接收数据 一、快速搭建SpringMVC框架1、配置分析2、准备项目3、Controller声明4、Spring MVC核心组件配置类5、SpringMVC环境搭建6、启动测试 二、SpringMVC接收数据1、访问路径设置1&#xff09;精准路径匹配2&#xff09;模糊路…...

C语言串讲-3之函数和数组

1&#xff0e;函数名是一个指针&#xff0c;保存函数地址入口。函数名是函数的入口地址。函数的入口地址称为函数指针。 2&#xff0e;传参--本质是创建副本 &#xff08;1&#xff09;实参与形参 &#xff08;2&#xff09;值传递&#xff0c;指针传递&#xff0c;引用传递 …...

设计模式-状态模式(State)

允许一个对象内部状态改变时改变它的行为&#xff0c;对象看起来似乎修改了它的类 问题&#xff1a; 状态模式和有限状态机紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中&#xff0c; 程序的行为都不相同&#xff0c; 且可瞬间从一个…...

c语言中的文件操作(2)

文件的打开-fopen 函数介绍 文件的打开方式 相对路径与绝对路径 文件关闭函数fclose 文件操作的正确流程 函数的介绍 文件的打开形式 相对路径与绝对路径 文件的关闭函数-fclose 正确的文件操作的流程 前言 通过前面的章节我们已经知道文件的基本的概念&#xff0c;我们如…...

【Verilog】case、casex、casez的区别

在case语句中&#xff0c;敏感表达式中与各项值之间的比较是一种全等比较&#xff0c;每一位都相同才认为匹配。 在casez语句中&#xff0c;如果分支表达式某些位的值为高阻z&#xff0c;那么对这些位的比较就会忽略&#xff0c;不予考虑&#xff0c;而只关注其他位的比较结果…...

Seata源码笔记(二)

Seata源码笔记&#xff08;二&#xff09; 配置相关的ConfigurationFactory静态代码块load()&#xff1a;融入spring获取value的方式Configuration的get方法拦截后&#xff0c;value取值优先级ObjectHolderPROPERTY_BEAN_MAP getInstancebuildConfiguration reload 基于incubar…...

【Java SE】接口类型

在 Java 中&#xff0c;接口&#xff08;Interface&#xff09;是一种引用类型&#xff0c;类似于特殊的抽象类&#xff0c;用于定义一组方法规范&#xff0c;而不提供具体的实现。接口可以包含成员属性&#xff0c;这些属性默认是常量。尽管每个类只能继承一个父类&#xff0c…...

[代码随想录Day10打卡] 理论基础 232.用栈实现队列 225. 用队列实现栈 20. 有效的括号 1047. 删除字符串中的所有相邻重复项

理论基础 队列先入先出。 栈先入后出。 具体的实现和用法根据语言的不同而不同。 参考的文章 https://programmercarl.com/%E6%A0%88%E4%B8%8E%E9%98%9F%E5%88%97%E7%90%86%E8%AE%BA%E5%9F%BA%E7%A1%80.html 232.用栈实现队列 这个定义入栈和出栈&#xff0c;往队列中加入…...

逻辑回归:给不确定性划界的分类大师

想象你是一名医生。面对患者的检查报告&#xff08;肿瘤大小、血液指标&#xff09;&#xff0c;你需要做出一个**决定性判断**&#xff1a;恶性还是良性&#xff1f;这种“非黑即白”的抉择&#xff0c;正是**逻辑回归&#xff08;Logistic Regression&#xff09;** 的战场&a…...

PHP和Node.js哪个更爽?

先说结论&#xff0c;rust完胜。 php&#xff1a;laravel&#xff0c;swoole&#xff0c;webman&#xff0c;最开始在苏宁的时候写了几年php&#xff0c;当时觉得php真的是世界上最好的语言&#xff0c;因为当初活在舒适圈里&#xff0c;不愿意跳出来&#xff0c;就好比当初活在…...

Debian系统简介

目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版&#xff…...

可靠性+灵活性:电力载波技术在楼宇自控中的核心价值

可靠性灵活性&#xff1a;电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中&#xff0c;电力载波技术&#xff08;PLC&#xff09;凭借其独特的优势&#xff0c;正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据&#xff0c;无需额外布…...

Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!

一、引言 在数据驱动的背景下&#xff0c;知识图谱凭借其高效的信息组织能力&#xff0c;正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合&#xff0c;探讨知识图谱开发的实现细节&#xff0c;帮助读者掌握该技术栈在实际项目中的落地方法。 …...

零基础设计模式——行为型模式 - 责任链模式

第四部分&#xff1a;行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习&#xff01;行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想&#xff1a;使多个对象都有机会处…...

AI,如何重构理解、匹配与决策?

AI 时代&#xff0c;我们如何理解消费&#xff1f; 作者&#xff5c;王彬 封面&#xff5c;Unplash 人们通过信息理解世界。 曾几何时&#xff0c;PC 与移动互联网重塑了人们的购物路径&#xff1a;信息变得唾手可得&#xff0c;商品决策变得高度依赖内容。 但 AI 时代的来…...

Xen Server服务器释放磁盘空间

disk.sh #!/bin/bashcd /run/sr-mount/e54f0646-ae11-0457-b64f-eba4673b824c # 全部虚拟机物理磁盘文件存储 a$(ls -l | awk {print $NF} | cut -d. -f1) # 使用中的虚拟机物理磁盘文件 b$(xe vm-disk-list --multiple | grep uuid | awk {print $NF})printf "%s\n"…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

【前端异常】JavaScript错误处理:分析 Uncaught (in promise) error

在前端开发中&#xff0c;JavaScript 异常是不可避免的。随着现代前端应用越来越多地使用异步操作&#xff08;如 Promise、async/await 等&#xff09;&#xff0c;开发者常常会遇到 Uncaught (in promise) error 错误。这个错误是由于未正确处理 Promise 的拒绝&#xff08;r…...