【干货拿走】JavaScript中最全的数据类型判断方法!!!!

简介: 【干货拿走】JavaScript中最全的数据类型判断方法!!!!

在 JavaScript 中,主要有七种基本数据类型Undefined、Null、Boolean、Number、String、Symbol、BigInt,还有一种复杂数据类型Object,其中包含了Data、function、Array、RegExp等。JavaScript 不支持任何创建自定义类型的机制,而所有值最终都将是上述8种数据类型之一。由于JavaScript 是一种动态类型语言,这意味着你可以在程序执行过程中改变变量的类型。

基本数据类型与引用数据类型的区别:基本数据类型是指存放在栈(stack)中的简单数据段,数据大小确定,内存空间大小可以分配,它们是直接按值存放的,所以可以直接按值访问引用类型是存放在堆(heap)内存中的对象,变量其实是保存的在栈内存中的一个指针(保存的是堆内存中的引用地址),这个指针指向堆内存。引用类型数据在栈内存中保存的实际上是对象在堆内存中的引用地址。通过这个引用地址可以快速查找到保存中堆内存中的对象。

那么,在实际工作代码开发中,有哪些方法去判断一个数据是哪种数据类型呢?这就是本篇文章要重点介绍的内容——JavaScript中的数据类型判断方法大全!

02

运算符typeof

typeof 运算符是 JavaScript 的基础知识点,尽管它存在一定的局限性(见下文),但在前端js的实际编码过程中,仍然是使用比较多的类型判断方式。因此,掌握该运算符的特点,对于写出好的代码,就会起到很大的帮助作用。

typeof 运算符可能返回的类型字符串有:string, boolean, number, bigint, symbol, undefined, function, object。

// string
typeof '123'; // 'string'
typeof String(1); // 'string'
// boolean
typeof true; // 'boolean'
typeof Boolean(); // 'boolean'
// number
typeof 1; // number
typeof Number(10); // number
typeof NaN;//number
// undefined
typeof a; // undefined
typeof undefined; // undefined
// symbol
typeof Symbol(); // 'symbol'
typeof Symbol('foo'); // 'symbol'
typeof Symbol.iterator; // 'symbol'
// bigint
typeof 42n; // 'bigint'
typeof BigInt(1); // 'bigint'
// function
typeof function () { return 1 }; // function
typeof console.log; //function
typeof class cs {}; // 'function'
typeof String; // 'function'
typeof RegExp; // 'function'
typeof new Function(); // 'function'
// object
typeof null; // object
typeof []; // object
typeof [1,2,3]; // object
typeof {'id':11}; //object
typeof {}; //object
typeof Math; // 'object'
typeof new Number(1); // 'object'


需要注意的是typeof null返回为object,因为特殊值null被认为是一个空的对象引用。这是 JavaScript 语言的一个历史遗留问题。在JavaScript 最初的版本中,使用 32 位的值表示一个变量,其中前 3 位用于表示值的类型。000 表示对象,010 表示浮点数,100 表示字符串,110 表示布尔值,和其他的值都被认为是指针。在这种表示法下,null 被解释为一个全零的指针,也就是说它被认为是一个空对象引用,因此 typeof null的结果就是 "object"。

typeof 的局限性:在于无法精确判断出 null、数组、对象、正则 的类型。引用类型,除了function返回function类型外,其它均返回object。所以如果要精准判断,还需要使用其他技术手段,或组合判断(见下文)。

03

属性constructor

在 JS 的原型链和原型对象中,会通过 new 一个构造函数,来创建实例对象。构造函数的原型对象上会有一个 constructor 属性,指向了构造函数自身,所以实例对象通过原型链访问 constructor 属性,就能找到自己的构造函数,也就是自己的类型了。

new String('a').constructor === String; // true
"a".constructor === String; // true
(1).constructor === Number; // true
new Number(1).constructor === Number; // true
true.constructor === Boolean; // true
new Function().constructor === Function; // true
Symbol(0).constructor === Symbol; // true; // true
BigInt(1).constructor === BigInt; // true
new Error().constructor === Error; // true
[].constructor === Array; // true
new Date().constructor === Date; // true
new RegExp().constructor === RegExp; // true
new Object().constructor === Object; // true


注意:

null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

函数的 constructor 不一定准确,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object。

String.prototype.constructor = function fn() {
    return {};
}
console.log("前端技术营".constructor)  // [Function: fn]
console.log("前端技术营".constructor === String) // false


04

instanceof

instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。也就是说检测实例对象是不是属于某个构造函数,可以用来做数据类型的检测。不能检测基本数据类型,只可用来判断引用数据。

// 不能检测基本数据类型
1 instanceof Number; // false
// 来检测引用数据
[] instanceof Array; // true
[] instanceof Object; // true
new Object() instanceof Object; // true
new Date() instanceof Date; // true
function Person(){}  
new Person() instanceof Person; //true
Person instanceof Object; //true
new Date() instanceof Object; //true
new Person instanceof Object; // true


通过上面代码可以看到,instanceof 既能够判断出 [ ] 是Array的实例,又能判断出 [ ] 也是Object的实例,这是为什么呢?

通过《 一文让你搞懂javascript中的构造函数、实例、原型、原型链,和它们之间的关系》这篇文章就可以明白其原因了。instanceof 能够判断出 [ ].__proto__ 指向 Array.prototype,而 Array.prototype.__proto__ 又指向了Object.prototype,最终Object.prototype.__proto__ 指向了null,标志着原型链的结束。因此,[ ]、Array、Object 就在内部形成了一条原型链。

缺点:

不能检测基本数据类型,只可用来判断引用数据,obj instanceof Type右操作数必须是函数或者 class。

2. 原型链可能被修改,导致检测结果不准确。

05

Object.prototype.toString

Object.prototype.toString——专业检测数据类型一百年! 它是一个专门检测数据类型的方法。

原理:当调用 Object.prototype.toString 时,JavaScript会将该调用传递给我们需要检查类型的对象。因为Object.prototype.toString是一个函数,所以传递给它的唯一参数是this,而且该参数是一个隐式参数。具体如下:Object.prototype.toString.call(obj),由于toString是Object.prototype上的方法,因此我们传递给它的参数应该是一个对象,而Object.prototype.toString方法本身却没有传递参数。这就是为什么我们需要用call将它与需要检查类型的对象连接起来。该方法可以指定函数内的this关键字上下文。因此,我们将检查类型的对象作为首个参数传递给了toString方法,并使用call方法将Object.prototype.toString作为一个函数来执行。这样JavaScript就会在上下文对象上执行Object.prototype.toString方法,从而返回一个表示该对象类型的字符串。

function checkDataType(data) {
    return Object.prototype.toString.call(data).slice(8, -1);
}
checkDataType(1); // Number
checkDataType('a'); // String
checkDataType(true); //Boolean
checkDataType(null); //Null
checkDataType(undefined); //Undefined
checkDataType(Symbol('b')); //Symbol
checkDataType(BigInt(10)); //BigInt
checkDataType([]); //Array
checkDataType({}); //Object
checkDataType(function fn() {}); //Function
checkDataType(new Date()); //Date
checkDataType(new RegExp()); //RegExp
checkDataType(new Error()); //Error
checkDataType(document); //HTMLDocument
checkDataType(window); //Window


编写一个函数,对返回的字符串从第8位做一个截取,截取到倒数第一位,再去做类型比较。

06

Array.isArray专业检测数组三十年

Array.isArray() 检查传递的值是否为Array。它不检查值的原型链,也不依赖于它所附加的 Array 构造函数。对于使用数组字面量语法或 Array 构造函数创建的任何值,它都会返回 true。

Array.isArray() 也拒绝原型链中带有 Array.prototype,而实际不是数组的对象,但 instanceof Array 会接受。

// 下面的函数调用都返回 true
Array.isArray([]);
Array.isArray([1]);
Array.isArray(new Array());
Array.isArray(new Array("a", "b", "c", "d"));
Array.isArray(new Array(3));
// 鲜为人知的事实:其实 Array.prototype 也是一个数组:
Array.isArray(Array.prototype);
// 下面的函数调用都返回 false
Array.isArray();
Array.isArray({});
Array.isArray(null);
Array.isArray(undefined);
Array.isArray(17);
Array.isArray("Array");
Array.isArray(true);
Array.isArray(false);
Array.isArray(new Uint8Array(32));
// 这不是一个数组,因为它不是使用数组字面量语法或 Array 构造函数创建的
Array.isArray({ __proto__: Array.prototype });


07

Number.isNaN专业检测NaN三十年

JS 中有一个特殊的数字——NaN,表示 not a number,不是一个数字,但它却归属于数字类型。在上文中我们知道 typeof NaN 返回number。NaN 用于表示不是一个数字,它不等于任何值,包括它本身。ES6 提供了 Number.isNaN 方法,它能判断一个值是否严格等于NaN。

Number.isNaN(NaN); //true
Number.isNaN(1); //false
Number.isNaN('abc'); //false;
Number.isNaN([]); //false;
Number.isNaN({}); //false


08

Symbol.toStringTag属性

上面的 Object.prototype.toString 方法,之所以对不同的数据类型,返回不同的标识字符串,就是因为 Symbol.toStringTag 。Symbol.toStringTag 是一个内置符号属性,它的值是一个字符串,用于表示一个对象的默认描述,也就是调用 Object.prototype.toString 会返回的内容。

const obj = {};
obj[Symbol.toStringTag] = 'ABCD';
console.log(Object.prototype.toString.call(obj))  // [object ABCD]


Symbol.toStringTag主要适用于需自定义类型的场景。

对于自定义对象,调用 Object.prototype.toString.call()方法,都只会返回 [object Object]。此时就可以使用 Symbol.toStringTag 来指定一个确定的类型了。


09

getPrototypeOf()

Object.getPrototypeOf() 静态方法返回指定对象的原型,即内部 [[Prototype]] 属性的值。

Object.getPrototypeOf([]) === Array.prototype; // true
Object.getPrototypeOf({}) === Object.prototype; // true
Object.getPrototypeOf(function fn(){}) === Function.prototype; // true
Object.getPrototypeOf(new Date()) === Date.prototype; // true
Object.getPrototypeOf(new RegExp()) === RegExp.prototype; // true
Object.getPrototypeOf(new Error()) === Error.prototype; // true


10

isPrototypeOf()

isPrototypeOf() 是 Object函数(类)的下的一个方法,用于判断当前对象是否为另外一个对象的原型,如果是就返回 true,否则就返回 false。

let obj = new Object();
console.log(Object.prototype.isPrototypeOf(obj)); // true


obj对象是Object的实例,所以obj对象的原型(__proto__)指向Object的原型(prototype),上面会输出true。

function Human() {}
let human = new Human();
console.log(Human.prototype.isPrototypeOf(human)); // true


因为human对象是Human的实例,所以human对象的原型(__proto__)指向Human的原型(prototype),上面会输出true。

JavaScript中内置类Number、String、Boolean、Function、Array因为都是继承Object,所以下面的输出也都是true。

Object.prototype.isPrototypeOf(Number); // true
Object.prototype.isPrototypeOf(String); // true
Object.prototype.isPrototypeOf(Boolean); // true
Object.prototype.isPrototypeOf(Array); // true
Object.prototype.isPrototypeOf(Function); // true


另外值得一提的是 Function.prototype 也是Object的原型,因为Object也是一个函数(类),它们是互相生成的。

Object.prototype.isPrototypeOf(Function); // true
Function.prototype.isPrototypeOf(Object); // true


与instanceof的区别:instanceof 作用的原理就是判断实例的原型链中能否找到类的原型对象(prototype),而 isPrototypeOf 又是判断类的原型对象(prototype)是否在实例的原型链上。这两个表达的意思是一致的,之是写法不同而已。

instanceof的写法:A instanceof B,isPrototypeOf的写法:B.prototype.isPrototypeOf(A)。

11

等值比较

直接通过与一个特定的值进行比较,从而判断数据的类型。主要适用undefined、 window、 document、 null 等。

const value = null;
console.log(value === null) // true
// 同时判断一个值是 undefined 或者 null
let value;
console.log(value == null) // true


如何判断当前脚本运行在浏览器还是node环境中?

this === window ? 'browser' : 'node'


通过判断Global对象是否为window,如果不为window,当前脚本没有运行在浏览器中。


目录
相关文章
|
20天前
|
前端开发 JavaScript
有没有方法可以保证在JavaScript中多个异步操作的执行顺序?
有没有方法可以保证在JavaScript中多个异步操作的执行顺序?
83 58
|
4月前
|
JavaScript 前端开发 程序员
前端原生Js批量修改页面元素属性的2个方法
原生 Js 的 getElementsByClassName 和 querySelectorAll 都能获取批量的页面元素,但是它们之间有些细微的差别,稍不注意,就很容易弄错!
|
4月前
|
监控 JavaScript Java
Node.js中内存泄漏的检测方法
检测内存泄漏需要综合运用多种方法,并结合实际的应用场景和代码特点进行分析。及时发现和解决内存泄漏问题,可以提高应用的稳定性和性能,避免潜在的风险和故障。同时,不断学习和掌握内存管理的知识,也是有效预防内存泄漏的重要途径。
349 62
|
2月前
|
JavaScript 前端开发 开发者
JavaScript字符串的常用方法
在JavaScript中,字符串处理是一个非常常见的任务。JavaScript提供了丰富的字符串操作方法,使开发者能够高效地处理和操作字符串。本文将详细介绍JavaScript字符串的常用方法,并提供示例代码以便更好地理解和应用这些方法。
63 13
|
4月前
|
JavaScript 前端开发 索引
js中DOM的基础方法
【10月更文挑战第31天】这些DOM基础方法是操作网页文档结构和实现交互效果的重要工具,通过它们可以动态地改变页面的内容、样式和行为,为用户提供丰富的交互体验。
|
4月前
|
缓存 JavaScript UED
js中BOM中的方法
【10月更文挑战第31天】
|
3月前
|
存储 JavaScript 前端开发
JavaScript中的数据类型以及存储上的差别
通过本文的介绍,希望您能够深入理解JavaScript中的数据类型及其存储差别,并在实际编程中灵活运用这些知识,以提高代码的性能和稳定性。
67 3
|
4月前
|
缓存 JavaScript 前端开发
JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用
本文深入讲解了 JavaScript 与 DOM 交互的基础及进阶技巧,涵盖 DOM 获取、修改、创建、删除元素的方法,事件处理,性能优化及与其他前端技术的结合,助你构建动态交互的网页应用。
103 5
|
4月前
|
JavaScript 前端开发
js中的bind,call,apply方法的区别以及用法
JavaScript中,`bind`、`call`和`apply`均可改变函数的`this`指向并传递参数。其中,`bind`返回一个新函数,不立即执行;`call`和`apply`则立即执行,且`apply`的参数以数组形式传递。三者在改变`this`指向及传参上功能相似,但在执行时机和参数传递方式上有所区别。
51 1
|
4月前
|
存储 JavaScript 前端开发
js中的数据类型
JavaScript 中的数据类型包括五种基本类型(String、Number、Undefined、Boolean、Null)和三种引用类型(Object、Array、Function,以及ES6新增的Symbol)。基本类型直接存储值,引用类型存储的是指向实际数据的内存地址。了解它们的区别对于掌握 JavaScript 的变量赋值和函数传参至关重要。
56 1

热门文章

最新文章