【JavaScript】js中判断变量类型的几种方式

【JavaScript】js中判断变量类型的几种方式

简言

在JavaScript中有好几种判断变量类型的方式,此篇主要探讨判断变量类型的几种方式和特点。

判断类的方式

typeof

typeof 运算符返回一个字符串,表示操作数的类型。

typeof operand

参数:

operand表示要返回类型的对象或基本类型的表达式。

特点:适合判断常见的基本类型,引用类型需要做兼容处理才能准确区分。

描述结果Undefined“undefined”Null“object”Boolean“boolean”Number“number”BigInt“bigint”String“string”Symbol“symbol”Function;classes也是函数)“function”其他任何对象“object”// 数值

typeof 37 === "number";

typeof 3.14 === "number";

typeof 42 === "number";

typeof Math.LN2 === "number";

typeof Infinity === "number";

typeof NaN === "number"; // 尽管它是 "Not-A-Number" (非数值) 的缩写

typeof Number(1) === "number"; // Number 会尝试把参数解析成数值

typeof Number("shoe") === "number"; // 包括不能将类型强制转换为数字的值

typeof 42n === "bigint";

// 字符串

typeof "" === "string";

typeof "bla" === "string";

typeof `template literal` === "string";

typeof "1" === "string"; // 注意内容为数字的字符串仍是字符串

typeof typeof 1 === "string"; // typeof 总是返回一个字符串

typeof String(1) === "string"; // String 将任意值转换为字符串,比 toString 更安全

// 布尔值

typeof true === "boolean";

typeof false === "boolean";

typeof Boolean(1) === "boolean"; // Boolean() 会基于参数是真值还是虚值进行转换

typeof !!1 === "boolean"; // 两次调用 !(逻辑非)运算符相当于 Boolean()

// Symbols

typeof Symbol() === "symbol";

typeof Symbol("foo") === "symbol";

typeof Symbol.iterator === "symbol";

// Undefined

typeof undefined === "undefined";

typeof declaredButUndefinedVariable === "undefined";

typeof undeclaredVariable === "undefined";

// 对象

typeof { a: 1 } === "object";

// 使用 Array.isArray 或者 Object.prototype.toString.call

// 区分数组和普通对象

typeof [1, 2, 4] === "object";

typeof new Date() === "object";

typeof /regex/ === "object";

// 下面的例子令人迷惑,非常危险,没有用处。避免使用它们。

typeof new Boolean(true) === "object";

typeof new Number(1) === "object";

typeof new String("abc") === "object";

// 函数

typeof function () {} === "function";

typeof class C {} === "function";

typeof Math.sin === "function";

instanceof

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

可以理解为:某个实例对象(变量)来自于某个构造函数,则返回true,否则返回false。

object instanceof constructor

参数:

object — 某个实例对象constructor — 某个构造函数。

特点:如果变量值是用new创建的,也可以使用它判断类型。

var simpleStr = "This is a simple string";

var myString = new String();

var newStr = new String("String created with constructor");

var myDate = new Date();

var myObj = {};

var myNonObj = Object.create(null);

simpleStr instanceof String; // 返回 false,非对象实例,因此返回 false

myString instanceof String; // 返回 true

newStr instanceof String; // 返回 true

myString instanceof Object; // 返回 true

myObj instanceof Object; // 返回 true,尽管原型没有定义

({}) instanceof Object; // 返回 true,同上

myNonObj instanceof Object; // 返回 false,一种创建非 Object 实例的对象的方法

myString instanceof Date; //返回 false

myDate instanceof Date; // 返回 true

myDate instanceof Object; // 返回 true

myDate instanceof String; // 返回 false

Object.prototype.constructor

Object 实例的 constructor 数据属性返回一个引用,指向创建该实例对象的构造函数。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。

除了 null 原型对象之外,任何对象都会在其 [[Prototype]] 上有一个 constructor 属性。使用字面量创建的对象也会有一个指向该对象构造函数类型的 constructor 属性,例如,数组字面量创建的 Array 对象和对象字面量创建的普通对象。

特点:不能判断null,且非基本类型判断可能会不准确。

非基本类型对象的 constructor 属性可以更改

const o1 = {};

o1.constructor === Object; // true

const o2 = new Object();

o2.constructor === Object; // true

const a1 = [];

a1.constructor === Array; // true

const a2 = new Array();

a2.constructor === Array; // true

const n = 3;

n.constructor === Number; // true

const arr = [];

arr.constructor = String;

arr.constructor === String; // true

arr instanceof String; // false

arr instanceof Array; // true

const foo = new Foo();

foo.constructor = "bar";

foo.constructor === "bar"; // true

Object.prototype.toString

所有继承自 Object.prototype 的对象(即,除了 null-prototype 对象之外的对象)都继承 toString() 方法。

要将基本的 Object.prototype.toString() 用于重写的对象(或者在 null 或 undefined 上调用它),你需要在它上面调用 Function.prototype.call() 或者 Function.prototype.apply(),将要检查的对象作为第一个参数传递(称为 thisArg)。

Function.prototype.call()和Function.prototype.apply() 结果相同

特点:基本类型和非基本类型都可以判断,不过不可靠,因为对象可以通过定义 Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为,从而导致意想不到的结果,Object.prototype.toString也可以更改。

const arr = [1, 2, 3];

arr.toString(); // "1,2,3"

Object.prototype.toString.call(arr); // "[object Array]"

const toString = Object.prototype.toString;

toString.call(new Date()); // [object Date]

toString.call(new String()); // [object String]

// Math has its Symbol.toStringTag

toString.call(Math); // [object Math]

toString.call(undefined); // [object Undefined]

toString.call(null); // [object Null]

通过定义 Symbol.toStringTag 属性来更改 Object.prototype.toString() 的行为:

const myDate = new Date();

Object.prototype.toString.call(myDate); // [object Date]

myDate[Symbol.toStringTag] = "myDate";

Object.prototype.toString.call(myDate); // [object myDate]

Date.prototype[Symbol.toStringTag] = "prototype polluted";

Object.prototype.toString.call(new Date()); // [object prototype polluted]

Object.prototype.toString直接更改将会使Object.prototype.toString.call报错

优化的类型判断方法

下面是mdn上的优化方法,你可以基于该方法进行扩展。

function type(value) {

if (value === null) {

return "null";

}

const baseType = typeof value;

// 基本类型

if (!["object", "function"].includes(baseType)) {

return baseType;

}

// Symbol.toStringTag 通常指定对象类的“display name”

// 它在 Object.prototype.toString() 中使用。

const tag = value[Symbol.toStringTag];

if (typeof tag === "string") {

return tag;

}

// 如果它是一个函数,其源代码以 "class" 关键字开头

if (

baseType === "function" &&

Function.prototype.toString.call(value).startsWith("class")

) {

return "class";

}

// 构造函数的名称;例如 `Array`、`GeneratorFunction`、`Number`、`String`、`Boolean` 或 `MyCustomClass`

const className = value.constructor.name;

if (typeof className === "string" && className !== "") {

return className;

}

// 在这一点上,没有合适的方法来获取值的类型,因此我们使用基本实现。

return baseType;

}

相关故事

绝地求生握把选择攻略:不同握把的作用与区别解析
365bet官方投注网址

绝地求生握把选择攻略:不同握把的作用与区别解析

灌顶是什么
365bet线上棋牌

灌顶是什么

复制多个控件内容至粘贴板;Access批量复制控件值的示例
365bet官方投注网址

复制多个控件内容至粘贴板;Access批量复制控件值的示例