js检测数据类型的几种方法总结

JavaScript 数据类型

  • number (基本类型)
  • string (基本类型)
  • boolean (基本类型)
  • null (基本类型):表示一个对象值不存在
  • undefined (基本类型):声明了,但没有赋值
  • symbol (ES6 - 基本类型)
  • bigInt (ES10 - 基本类型)
  • object (引用类型,包含 function[ ]{ }

特点:

  • 基本类型的特点:直接存储在栈(stack)内存中的数据
  • 引用类型的特点:存储的是该对象在栈中引用,真实的数据存放在堆(heap)内存中

在这里插入图片描述


一、typeof

  • typeof在对值类型numberstringboolean symbolundefinedfunctionbigint的反应是精准的;

  • 但对于对象{ }数组[ ]null 都会返回 object

console.log(typeof ""); // string
console.log(typeof 1); // number
console.log(typeof NaN); // number
console.log(typeof true); // boolean
console.log(typeof Symbol(1)) // "symbol"
console.log(typeof BigInt(11)) // "bigint"
console.log(typeof undefined); // undefined
console.log(typeof function(){}); // function

console.log(typeof null); // object   JavaScript语言设计上的一个历史遗留问题
console.log(typeof []); // object  // 引用类型
console.log(typeof {}); //object  // 引用类型

typeof null 返回 “object” 的行为是一个历史上的错误。这主要是因为早期的 JavaScript 设计中存在一些概念上的混淆和遗留问题。

function虽然是引用类型,但typeof function却不是object,而是function
这是因为JavaScript语言规范中明确定义了typeof运算符对于函数应返回 function。这种设计决策是基于实用性和类型检测的明确性。


二、instanceof

instanceof可以正确判断对象的类型,其内部运行机制是判断在其原型链中能否找到该类型的原型

  • instanceof 判断一个实例是否属于某种类型

  • instanceof 运算符只能正确判断引用数据类型,而不能判断基本数据类型

  • instanceof可以用来测试一个对象在其原型链中是否存在一个构造函数的 prototype 属性

// 检测构造函数B的原型是否有出现在对象A的原型链上。
A instanceof B 

[] instanceof Array // true
[].__proto__ == Array.prototype // true

1. 基础类型

console.log("1" instanceof String); // false
console.log(1 instanceof Number); // false
console.log(NaN instanceof Number); // false
console.log(true instanceof Boolean); // false

上面之所以都返回false是因为不是对象,而是基本类型。

封装成对象后才返回true,如下:

console.log(new String("1") instanceof String); // true
console.log(new Number(1) instanceof Number); // true
console.log(new Number(NaN) instanceof Number); // true
console.log(new Boolean(true) instanceof Boolean); // true

new是封装成对象,而没有new的只是基础类型转换,还是基础类型

一个是引用类型,一个是基本类型

console.log(new String("1"), "1");
console.log(new Number(1), 1);
console.log(new Number(NaN), NaN);
console.log(new Boolean(true), true);

在这里插入图片描述

2. 复杂类型/引用类型

console.log([] instanceof Array); // true    =>   [].__proto__ === Array.prototype
console.log([] instanceof Object); // true   =>   Array.prototype.__proto__ === Object.prototype

console.log({} instanceof Object); //true   =>   {}.__proto__ === Object.prototype

console.log(function(){} instanceof Function); // true  =>   function(){}.__proto__ === Function.prototype
console.log(function(){} instanceof Object); // true    =>   Function.prototype.__proto__ === Object.prototype

console.log((new Number(1)) instanceof Number); // true   =>   new Number(1).__proto__ === Number.prototype
console.log((new Number(1)) instanceof Object); // true   =>   Number.prototype.__proto__ === Object.prototype

小坑(因为instanceof 运算符只能正确判断引用数据类型,而不能判断基本数据类型)

console.log(undefined instanceof undefined); // 报错
console.log(null instanceof null); // 报错

巨坑

console.log(null instanceof Object); // false
但
console.log(typeof null); // object

三、constructor

constructor 是每个实例对象都拥有的属性

constructor有两个作用:

  1. 判断数据的类型;
  2. 对象实例通过 constrcutor 对象访问它的构造函数(实例的constrcutor属性,指向构造函数本身);
function Hello() {}; // 构造函数
var h = new Hello(); // 实例化对象

console.log(Hello.prototype.constructor == Hello); // true
console.log(h.constructor == Hello); // true ()
console.log(("1").constructor === String); // true
console.log((1).constructor === Number); // true
console.log((NaN).constructor === Number); // true
console.log((true).constructor === Boolean); // true
console.log(([]).constructor === Array); // true
console.log((function () {}).constructor === Function); // true
console.log(({}).constructor === Object); // true
console.log((Symbol(1)).constructor === Symbol); // true

console.log((null).constructor === Null); // 报错
console.log((undefined).constructor === Undefined); // 报错

costructor来判断类型看起来是完美的,然而,如果我创建一个对象,更改它的原型,这种方式也变得不可靠了

function Fn(){};
Fn.prototype=new Array(); // 改变原型
var f=new Fn();

console.log(f.constructor===Fn);    // false
console.log(f.constructor===Array); // true 

这里声明了一个Fn的构造函数,并且把他的原型指向了Array的原型,所以这种情况下,constructor也显得力不从心了。


四、Object.prototype.toString.call()

使用 Object 对象的原型方法 toString 来判断数据类型:完美精准 的返回各种数据类型

const a = Object.prototype.toString;

console.log(a.call(1)); // [object Number]
console.log(a.call("1")); // [object String]
console.log(a.call(NaN)); // [object Number]
console.log(a.call(true)); // [object Boolean]
console.log(a.call(Symbol(1))); // [object Symbol]
console.log(a.call(null)); // [object Null]
console.log(a.call(undefined)); // [object Undefined]
console.log(a.call([])); // [object Array]
console.log(a.call({})); // [object Object]
console.log(a.call(function () {})); // [object Function]


function Fn(){};
Fn.prototype=new Array(); // 改变原型
var f=new Fn();
console.log(a.call(Fn)); // [object Function]

简单封装

// 定义检测数据类型的功能函数
function checkedType(target) {
	return Object.prototype.toString.call(target).slice(8, -1);
}

console.log(checkedType(1)); // Number
console.log(checkedType("1")); // String
console.log(checkedType(NaN)); // Number
console.log(checkedType(true)); // Boolean
console.log(checkedType(Symbol(1))); // Symbol
console.log(checkedType(null)); // Null
console.log(checkedType(undefined)); // Undefined
console.log(checkedType([])); // Array
console.log(checkedType({})); // Object
console.log(checkedType(function () {})); // Function

检测原理

首先,这句话的意思是让我们用Object原型上的toString方法作用在传入的obj的上下文中(通过callthis指向obj),那么我们知道数组本身也有toString()方法,那我们为什么非要用Object上的呢?

Object.toString() // "function Object() { [native code] }"
Object.prototype.toString() // "[object Object]"

toStringObject的原型方法,而Array 、Function等类型作为Object的实例,都重写toString方法。不同的对象类型调用toString方法时,根据原型链的知识,调用的是对应的重写之后的toString方法Function类型返回内容为函数体的字符串,Array类型返回元素组成的字符串…),而不会去调用Object上原型toString方法(返回对象的具体类型),所以采用obj.toString()不能得到其对象类型,只能将obj转换为字符串类型;因此,在想要得到对象的具体类型时,应该调用Object上原型toString方法。

我们可以验证一下,将数组的toString方法删除,看看会是什么结果:

var arr=[1,2,3];

console.log(Array.prototype.hasOwnProperty("toString"));//true
console.log(arr.toString());//1,2,3

delete Array.prototype.toString;//delete操作符可以删除实例属性

console.log(Array.prototype.hasOwnProperty("toString"));//false

// 删除后的数组再次使用 toString() 时,会向上层访问这个方法,即 Object 的 toString()
console.log(arr.toString());//"[object Array]"

当我们把Array自身的toString()方法删除之后,再次使用它时,由原型链它会向上查找这个方法,即Object的toString(),也便将Object上的toString()方法作用在数组上,得出其数据类型[object Array]


五、__proto__

var arr = [];
arr.__proto__ === Array.prototype; // true

var obj = {};
obj.__proto__ === Object.prototype; // true

var str = '';
str.__proto__ === String.prototype; // true

var num = 0;
num.__proto__ === Number.prototype; // true

六、 其他

  1. 通过ES6的Array.isArray()来判断数组

    Array.isArrray(obj);
    
  2. 通过Array.prototype.isPrototypeOf 判断一个对象是否存在于另一个对象的原型链中

    let arr = [1, 2, 3];  
      
    console.log(Array.prototype.isPrototypeOf(arr));  // 输出: true  
      
    let obj = {};  
      
    console.log(Array.prototype.isPrototypeOf(obj));  // 输出: false
    
  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猫老板的豆

你的鼓励将是我创作的最大动力~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值