Javascript高级—如何实现一个类型判断函数?
实现一个类型判断函数
- 判断null
- 判断基础类型
- 使用
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] 注意: 一定是使用call来调用,不然是判断的Object.prototype的类型 之所以要先判断是否为基本类型是因为:虽然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 给地图添加碰撞体 总结 前言 今天不加班,有空闲时间。争取一天学一课,养成习惯 开发环境 Unity 6windows 11vs studio 2022Unity2022.2 最新教程《勇士传说》入门到进阶ÿ…...
【深圳大学/大学物理实验2】弗兰克-赫兹实验预习题参考
一、单选题 共 13 小题 共 78 分 1. (6分)第一栅极电压UG1、第二栅极电压UG2和减速电压UP的作用分别是( ) 学生答案:C √ A. 使电子加速,消除阴极电子散射,使电子减速 B. 产生并加速电子,使电子加速&…...
vue2.7.14 + vant + vue cli脚手架转vite启动运行问题记录
文章目录 前言方案一(借用插件转换)启动命令,转换方案一转换遇到的问题 方案二(手动调整)方案两者对比小结 前言 vue cli 脚手架转成vite启动 简单说说这个项目的一些底层基本结构哈,以及写这篇博客的目的…...
Java基础-内部类与异常处理
(创作不易,感谢有你,你的支持,就是我前行的最大动力,如果看完对你有帮助,请留下您的足迹) 目录 一、Java 内部类 什么是内部类? 使用内部类的优点 访问局部变量的限制 内部类和继承 内部…...
vue2或vue3的name属性有什么作用?
在 Vue.js(无论是 Vue 2 还是 Vue 3)中,组件的 name 属性有几个重要的用途。虽然它不是必须的,但在某些情况下非常有用。以下是 name 属性的一些主要作用: 1. 调试工具 Vue Devtools 和其他调试工具会使用组件的 nam…...
【FOC进阶日记】实战篇③ 电机关键数据采集方法
作者 | 量子君 微信公众号 | 极客工作室 【FOC进阶日记】专栏目录 第一章 实战篇① FOC与SVPWM详解 第二章 实战篇② 自发电控制算法 第三章 实战篇③ 电机关键数据采集方法 文章目录 前言一、M法(从路程入手):二、T法(从时间入手)三、M/T测速法:四、实现过程:总结前言…...
XSS安全基础
欢迎关注公众号【测试开发备忘录】,交流学习经验 XSS 类型: 反射型XSS:简单的把用户输入的数据“反射”给浏览器,将恶意链接嵌入,非持久; 存储型XSS:把用户输入的数据“存储”在服务端…...
【计网不挂科】计算机网络期末考试——【选择题&填空题&判断题&简述题】试卷(3)
前言 大家好吖,欢迎来到 YY 滴计算机网络 系列 ,热烈欢迎! 本章主要内容面向接触过C的老铁 本博客主要内容,收纳了一部门基本的计算机网络题目,供yy应对期中考试复习。大家可以参考 本章是去答案版本。带答案的版本在下…...
516.最长回文子序列
刷算法题: 第一遍:1.看5分钟,没思路看题解 2.通过题解改进自己的解法,并且要写每行的注释以及自己的思路。 3.思考自己做到了题解的哪一步,下次怎么才能做对(总结方法) 4.整理到自己的自媒体平台。 5.再刷重复的类…...
leetcode hot100【LeetCode 114.二叉树展开为链表】java实现
LeetCode 114.二叉树展开为链表 题目描述 给你二叉树的根结点 root ,请你将它展开为一个单链表: 展开后的单链表应该同样使用 TreeNode ,其中 right 子指针指向链表中下一个结点,而左子指针始终为 null 。 展开后的单链表应该与…...
SpringMVC学习记录(二)之接收数据
SpringMVC学习记录(二)之接收数据 一、快速搭建SpringMVC框架1、配置分析2、准备项目3、Controller声明4、Spring MVC核心组件配置类5、SpringMVC环境搭建6、启动测试 二、SpringMVC接收数据1、访问路径设置1)精准路径匹配2)模糊路…...
C语言串讲-3之函数和数组
1.函数名是一个指针,保存函数地址入口。函数名是函数的入口地址。函数的入口地址称为函数指针。 2.传参--本质是创建副本 (1)实参与形参 (2)值传递,指针传递,引用传递 …...
设计模式-状态模式(State)
允许一个对象内部状态改变时改变它的行为,对象看起来似乎修改了它的类 问题: 状态模式和有限状态机紧密相关。其主要思想是程序在任意时刻仅可处于几种有限的状态中。 在任何一个特定状态中, 程序的行为都不相同, 且可瞬间从一个…...
c语言中的文件操作(2)
文件的打开-fopen 函数介绍 文件的打开方式 相对路径与绝对路径 文件关闭函数fclose 文件操作的正确流程 函数的介绍 文件的打开形式 相对路径与绝对路径 文件的关闭函数-fclose 正确的文件操作的流程 前言 通过前面的章节我们已经知道文件的基本的概念,我们如…...
【Verilog】case、casex、casez的区别
在case语句中,敏感表达式中与各项值之间的比较是一种全等比较,每一位都相同才认为匹配。 在casez语句中,如果分支表达式某些位的值为高阻z,那么对这些位的比较就会忽略,不予考虑,而只关注其他位的比较结果…...
Seata源码笔记(二)
Seata源码笔记(二) 配置相关的ConfigurationFactory静态代码块load():融入spring获取value的方式Configuration的get方法拦截后,value取值优先级ObjectHolderPROPERTY_BEAN_MAP getInstancebuildConfiguration reload 基于incubar…...
【Java SE】接口类型
在 Java 中,接口(Interface)是一种引用类型,类似于特殊的抽象类,用于定义一组方法规范,而不提供具体的实现。接口可以包含成员属性,这些属性默认是常量。尽管每个类只能继承一个父类,…...
[代码随想录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.用栈实现队列 这个定义入栈和出栈,往队列中加入…...
C++:std::is_convertible
C++标志库中提供is_convertible,可以测试一种类型是否可以转换为另一只类型: template <class From, class To> struct is_convertible; 使用举例: #include <iostream> #include <string>using namespace std;struct A { }; struct B : A { };int main…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
C# SqlSugar:依赖注入与仓储模式实践
C# SqlSugar:依赖注入与仓储模式实践 在 C# 的应用开发中,数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护,许多开发者会选择成熟的 ORM(对象关系映射)框架,SqlSugar 就是其中备受…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Web 架构之 CDN 加速原理与落地实践
文章目录 一、思维导图二、正文内容(一)CDN 基础概念1. 定义2. 组成部分 (二)CDN 加速原理1. 请求路由2. 内容缓存3. 内容更新 (三)CDN 落地实践1. 选择 CDN 服务商2. 配置 CDN3. 集成到 Web 架构 …...
重启Eureka集群中的节点,对已经注册的服务有什么影响
先看答案,如果正确地操作,重启Eureka集群中的节点,对已经注册的服务影响非常小,甚至可以做到无感知。 但如果操作不当,可能会引发短暂的服务发现问题。 下面我们从Eureka的核心工作原理来详细分析这个问题。 Eureka的…...
Hive 存储格式深度解析:从 TextFile 到 ORC,如何选对数据存储方案?
在大数据处理领域,Hive 作为 Hadoop 生态中重要的数据仓库工具,其存储格式的选择直接影响数据存储成本、查询效率和计算资源消耗。面对 TextFile、SequenceFile、Parquet、RCFile、ORC 等多种存储格式,很多开发者常常陷入选择困境。本文将从底…...
