0

深度解析javaScript常见数据类型检查校验

 2 years ago
source link: https://www.fly63.com/article/detial/11432
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

在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()

在使用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常见数据类型检查校验

链接: https://www.fly63.com/article/detial/11432


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK