前言

在JavaScript中,数据类型分为两大类,一种是基础数据类型,另一种则是复杂数据类型,又叫引用数据类型

  • 基础数据类型:数字Number 字符串String 布尔Boolean Null Undefined Symbols BigInt
  • 引用数据类型:日期Dete,对象Object,数组Array,方法Function, 正则regex,带键的集合:Maps, Sets, WeakMaps, WeakSets

基础数据类型和引用数据类型的区别,在之前深拷贝的文章中提到过,这里不做详细赘述。

传送门:javaScript中深拷贝和浅拷贝简单梳理

常见的几种数据校验方式

接下来会针对下面几种数据类型,进行校验

// 基本数据类型
let str = "abc";
let num = 123;
let boo = true;
let undef = undefined;
let testNull = null;
let symb = Symbol("user");
let bigInt = BigInt(9007199254740999); // 复杂-引用数据类型
let arr = [1, 2, 3, 4];
let func = function () {};
let obj = {};
let date1 = new Date();
let setObj1 = new Set();
let setObj2 = new Set([1, 2, 3]);
let mapObj = new Map();

typeof操作符

typeof操作符,会返回一个字符串,表示未经计算的操作数的类型

/**
* typeof 操作符
*
* 返回一个字符串,表示未经计算的操作数的类型。
*
* */
console.log(typeof str); // string
console.log(typeof num); // number
console.log(typeof boo); // boolean
console.log(typeof undef); // undefined
console.log(typeof testNull); // object
console.log(typeof symb); // symbol
console.log(typeof bigInt); // bigint
console.log(typeof Object(bigInt)); // object
console.log(typeof arr); // object
console.log(typeof func); // function
console.log(typeof obj); // object
console.log(typeof date1); // object
console.log(typeof setObj1); // object
console.log(typeof setObj2); // object
console.log(typeof mapObj); // object
小结

使用typeof操作符的时候,我们可以看到一些较为特殊的情况:

  • null,数组array,set,map 返回的是对象object

instanceof

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

/**
*
* instanceof
*
* 用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
*
* */ console.log(str instanceof String); // false console.log(new String("abc") instanceof String); // true console.log(num instanceof Number); // false console.log(new Number(123) instanceof Number); // true console.log(boo instanceof Boolean); // false console.log(new Boolean(true) instanceof Boolean); // false console.log(undef instanceof undefined);
// Uncaught TypeError: Right-hand side of 'instanceof' is not an object console.log(testNull instanceof null);
// Uncaught TypeError: Right-hand side of 'instanceof' is not an object console.log(symb instanceof Symbol); // false
// Symbol不是构造函数,没有new操作符 console.log(bigInt instanceof BigInt); // false console.log(Object(BigInt("22")) instanceof Object); // true console.log(Object(BigInt("22")) instanceof BigInt); // true console.log(arr instanceof Array); // true console.log(arr instanceof Object); // true console.log(func instanceof Function); // true console.log(func instanceof Object); // true console.log(obj instanceof Object); // true console.log(obj instanceof Function); // false console.log(null instanceof Object); // false console.log(date1 instanceof Object); // true console.log(setObj1 instanceof Object); // true console.log(setObj2 instanceof Object); // true console.log(mapObj instanceof Object); // true console.log(setObj1 instanceof Array); // false console.log(setObj2 instanceof Array); // false console.log(mapObj instanceof Array); // false

constructor


/**
* constructor
*
* 返回创建实例对象的 构造函数的引用。
*
* 注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串
*
* 构造函数.prototype.constructor()
*
* */ // 基本数据类型
let str = "abc";
let num = 123;
let boo = true;
let undef = undefined;
let testNull = null;
let symb = Symbol("user");
let bigInt = BigInt(9007199254740999); // 复杂-引用数据类型
let arr = [1, 2, 3, 4];
let func = function () {};
let obj = {};
let date1 = new Date();
function constructorFn() {
this.name = "11";
}
let con1 = new constructorFn();
let setObj1 = new Set();
let setObj2 = new Set([1, 2, 3]);
let mapObj = new Map(); console.log(str.constructor); // String console.log(num.constructor); // Number console.log(boo.constructor); // Boolean // console.log(testUndefined.constructor); // Cannot read property 'constructor' of undefined // console.log(testNull.constructor); // Cannot read property 'constructor' of null
console.log(symb.constructor); // Symbol console.log(bigInt.constructor); // BigInt console.log(arr.constructor); // Array console.log(func.constructor); // Function console.log(obj.constructor); // Object console.log(date1.constructor); // Date console.log(constructorFn.constructor); // Function console.log(con1.constructor); // constructorFn console.log(setObj1.constructor); // Set console.log(setObj2.constructor); // Set console.log(mapObj.constructor); // Map /**
*
* 构造函数校验
*
* */ console.log(Function.constructor); // Function
console.log(Object.constructor); // Function
console.log(Array.constructor); // Function
console.log(Date.constructor); // Function

Object.prototype.toString.call && Object.prototype.toString.apply

Object.prototype.toString()

在使用Object.prototype.toString.call或者Object.prototype.toString.apply检查数据类型之前,我们先了解一下Object.prototype.toString和JavaScript中的构造函数Function的原型方法apply和call:

/**
* 返回一个表示该对象的字符串
*
* Object.prototype.toString()
*
* 每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。
* 默认情况下,toString() 方法被每个 Object 对象继承。
*
* 如果此方法在自定义对象中未被覆盖,toString() 返回 "[object type]",其中 type 是对象的类型。以下代码说明了这一点:
*
* */ let isObj = { name: "zhangsan" };
let isBoolean = true;
let isNumber = new Number(123);
let isString = "abc";
let isFun = new Function();
console.log(isObj.toString()); // [object Object]
console.log(isBoolean.toString()); // true
console.log(isNumber.toString()); // 123
console.log(isString.toString()); // abc
console.log(new Date().toString()); // Thu Apr 28 2022 16:37:19 GMT+0800 (中国标准时间)
console.log(isFun.toString()); // function anonymous() {}
call && apply
/**
*
* call() 使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数,function.call(thisArg, arg1, arg2, ...)
*
* apply() 使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数,unc.apply(thisArg, [argsArray])
*
* */ // call基本使用;
function a() {
console.log(this);
} function b() {
console.log(this);
}
a.call(b); // function b() {}
b.call(a); // function a() {}
  • call和apply最简单的例子表明了,改变了当前方法的this指向
  • 同时这两个方法的区别在于传参的方式

Object.prototype.toString结合Function.prototype.call && apply


/**
*
* 使用 toString() 检测对象类型可以通过 toString() 来获取每个对象的类型。
* 为了每个对象都能通过 Object.prototype.toString() 来检测,
* 需要以 Function.prototype.call() 或者 Function.prototype.apply() 的形式来调用,传递要检查的对象作为第一个参数,称为 thisArg。
*
* 那么 Object.prototype.toString 相当于 原生构造函数的实例化对象isNumber,传参数给Object.prototype.toString执行
* 实际上相当于 toString.call(new ***);
*
* */ let str = "abc";
let num = 123;
let boo = true;
let undef = undefined;
let testNull = null;
let symb = Symbol("user");
let bigInt = BigInt(9007199254740999); // 复杂-引用数据类型
let arr = [1, 2, 3, 4];
let func = function () {};
let obj = {};
let date1 = new Date();
function testFun() {}
let newTest = new testFun();
let newFun = new Function();
let setObj1 = new Set();
let setObj2 = new Set([1, 2, 3]);
let mapObj = new Map(); console.log(Object.prototype.toString.apply(new String("sss"))); // [object String] console.log(Object.prototype.toString.apply(str)); // [object String] console.log(Object.prototype.toString.call(num)); // [object Number] console.log(Object.prototype.toString.call(boo)); // [object Boolean] console.log(Object.prototype.toString.call(undef)); // [object Undefined] console.log(Object.prototype.toString.call(testNull)); // [object Null] console.log(Object.prototype.toString.call(symb)); // [object Symbol] console.log(Object.prototype.toString.call(Object(bigInt))); // [object BigInt] console.log(Object.prototype.toString.call(bigInt)); // [object BigInt] console.log(Object.prototype.toString.apply(arr)); // [object Array] console.log(Object.prototype.toString.call(func)); // [object Function] console.log(Object.prototype.toString.call(obj)); // [object Object] console.log(Object.prototype.toString.call(date1)); // [object Date] console.log(Object.prototype.toString.call(testFun)); // [object Function] console.log(Object.prototype.toString.call(newTest)); // [object Object] console.log(Object.prototype.toString.call(newFun)); // [object Function] console.log(Object.prototype.toString.call(setObj1)); // [object Set] console.log(Object.prototype.toString.call(setObj2)); // [object Set] console.log(Object.prototype.toString.call(mapObj)); // [object Map]

其他校验数据类型的方法:

判断是否是数组:
console.log(Array.isArray([1, 2])); // true

判断一个对象是否是空对象
// 判断空对象
function isEmptyObj(obj) {
for (name in obj) {
console.log(name);
return false; // 不是空对象
}
return true;
}
console.log(isEmptyObj({})); // true

总结

  • 不管是typeof操作符,还是其他的操作方法,都有各自的缺陷
  • 在日常的开发过程中,我们需要知道当前操作的是对象,还是构造函数生成的对象或者方法,才能针对当前需要判断的数据类型,采用最适合的方法
  • Object.prototype.toString.call或者Object.prototype.toString.apply应该是最完善的方法,在我们不确定是否是引用类型或者基本数据类型的时候,建议作为首选
  • 在了解这些判断数据类型的方式之前或者说存有疑问:为什么array数组在使用instanceof和typeof 校验Object的时候都成立,这时候需要去了解一下引用数据类型的具体内容
  • 以上判断数据类型的方法,可以在项目开发过程中,可以写入到utils公共方法当中,作为开发中进行使用。
  • 更多用法等待补充。

源码地址

文章个人博客地址:深度解析javaScript常见数据类型检查校验

欢迎关注公众号:程序猿布欧,不定期更新一些前端入门文章

创作不易,转载请注明出处和作者。

深度解析javaScript常见数据类型检查校验的更多相关文章

  1. 深度解析javascript中的浅复制和深复制

    原文:深度解析javascript中的浅复制和深复制 在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null ...

  2. Javascript常见数据类型API

    1 - 内置对象 1.1 内置对象 ​ JavaScript 中的对象分为3种:自定义对象 .内置对象. 浏览器对象 ​ 前面两种对象是JS 基础 内容,属于 ECMAScript: 第三个浏览器对象 ...

  3. Angular 1 深度解析:脏数据检查与 angular 性能优化

    TL;DR 脏检查是一种模型到视图的数据映射机制,由 $apply 或 $digest 触发. 脏检查的范围是整个页面,不受区域或组件划分影响 使用尽量简单的绑定表达式提升脏检查执行速度 尽量减少页面 ...

  4. [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析

    [WebKit内核] JavaScript引擎深度解析--基础篇(一)字节码生成及语法树的构建详情分析 标签: webkit内核JavaScriptCore 2015-03-26 23:26 2285 ...

  5. 42套JavaScript深度解析教学视频!合集

    本文首发于:风云社区SCOEE(社区旨在普惠软件.图片.音乐.视频.素材.文档等互联网资源.为大众提供多样化的服务,以及主要涵盖学术科学.电脑技术.文化人文.体育健身等领域的知识和信息,获得用户的支持 ...

  6. mybatis 3.x源码深度解析与最佳实践(最完整原创)

    mybatis 3.x源码深度解析与最佳实践 1 环境准备 1.1 mybatis介绍以及框架源码的学习目标 1.2 本系列源码解析的方式 1.3 环境搭建 1.4 从Hello World开始 2 ...

  7. 程序员收藏必看系列:深度解析MySQL优化(二)

    程序员收藏必看系列:深度解析MySQL优化(一) 性能优化建议 下面会从3个不同方面给出一些优化建议.但请等等,还有一句忠告要先送给你:不要听信你看到的关于优化的“绝对真理”,包括本文所讨论的内容,而 ...

  8. Kafka深度解析

    本文转发自Jason’s Blog,原文链接 http://www.jasongj.com/2015/01/02/Kafka深度解析 背景介绍 Kafka简介 Kafka是一种分布式的,基于发布/订阅 ...

  9. java内存分配和String类型的深度解析

    [尊重原创文章出自:http://my.oschina.net/xiaohui249/blog/170013] 摘要 从整体上介绍java内存的概念.构成以及分配机制,在此基础上深度解析java中的S ...

随机推荐

  1. Constant Pool和String Constant Pool详解

    Constant Pool常量池的概念: 在讲到String的一些特殊情况时,总会提到String Pool或者Constant Pool,但是我想很多人都不太明白Constant Pool到底是个怎 ...

  2. BMZCTF WEB_ezeval

    WEB_ezeval 进入环境,源码给出 <?php highlight_file(__FILE__); $cmd=$_POST['cmd']; $cmd=htmlspecialchars($c ...

  3. ubuntu+ROS安装turtulebot3

    0 简介 Turtlebot是一种室内移动机器人,搭载激光传感器,使机器有精确的距离感知能力.通过搭建仿真环境,可以在没有硬件支持的情况下进行仿真和编程,并熟悉ros系统.环境使Ubuntu16.04 ...

  4. 惯性传感器(IMU)

    近两年来,车联网.自动驾驶.无人驾驶.汽车智能化.网联化等成为了汽车行业的热点话题,未来汽车一定是朝着安全.可靠及舒适的方向发展.而这一切背后的发展都离不开传感器的作用,今天我们就来聊聊用途越来越广的 ...

  5. 5V转10.5V原理图

  6. 二、cadence焊盘与封装制作操作步骤详细说明

    一.焊盘制作 1.打开Pad Designer软件,新建文件--设置保存路径和焊盘名称(规范命名) 2.Parameters--设置单位--过孔类型--是否镀金 3.Layers--single la ...

  7. Java到底是编译还是解释型语言?编译和解释型语言有什么区别?

    7.java语言执行过程与方式: 编译型语言: 是指使用专门的编译器.针对特定平台(操作系统)将某种高级语言源程序一次性"翻译"成可被该平台硬件运行的机器码(包括指令和数据),并包 ...

  8. linux-RHEL7.0 —— 《Linux就该这么学》阅读笔记

    目录 linux-RHEL7.0 安装部署 修改root密码 RPM(红帽软件包管理器) YUM(软件仓库) Systemd初始化进程 总结 linux命令 帮助命令 man 系统工作命令 echo ...

  9. Mybatis 多表实现多对多查询、添加操作

    Mybatis 多表实现多对多查询.添加操作 学习内容: 1. 多对多之添加操作 1.1.需求 1.2.数据库表(多对多数据库设计需要设计中间表) 1.3.类设计 1.4.Mapper 接口和 Map ...

  10. Mybatis实现批量删除数据

    Mybatis实现批量删除操作 学习内容: 1. 使用 2. 代码实现 2.1 UserMapper.java 接口 2.2 UserMapper.xml 总结: 学习内容: 1. 使用 这里通过动态 ...