yuanyuanbyte / Blog

圆圆的博客,预计写七个系列:JavaScript深入系列、JavaScript专题系列、网络系列、Webpack系列、Vue系列、JavaScript基础系列、HTML&CSS应知应会系列。
306 stars 125 forks source link

JavaScript 深入系列之数据类型检测 #94

Open yuanyuanbyte opened 2 years ago

yuanyuanbyte commented 2 years ago

本系列的主题是 JavaScript 深入系列,每期讲解一个技术要点。如果你还不了解各系列内容,文末点击查看全部文章,点我跳转到文末

如果觉得本系列不错,欢迎 Star,你的支持是我创作分享的最大动力。

一文搞定 JavaScript 的数据类型检测

1. typeof

对于原始数据类型,我们可以使用 typeof 操作符来判断他的数据类型:

console.log(typeof "");
console.log(typeof 1);
console.log(typeof true);
console.log(typeof null);
console.log(typeof undefined);
console.log(typeof []);
console.log(typeof function(){});
console.log(typeof {});

看看控制台输出什么

可以看到,typeof 对于基本数据类型判断是没有问题的,但是遇到引用数据类型(如:Array)是不起作用的。

typeof null

// JavaScript 诞生以来便如此
typeof null === 'object';

在 JavaScript 最初的实现中,JavaScript 中的值是由一个表示类型的标签和实际数据值表示的。对象的类型标签是 0。由于 null 代表的是空指针(大多数平台下值为 0x00),因此,null 的类型标签是 0,typeof null 也因此返回 "object"。

曾有一个 ECMAScript 的修复提案(通过选择性加入的方式),但被拒绝了。该提案会导致 typeof null === 'null'。

2. instanceof

typeof 操作符对于原始类型的判断还差强人意,但他是没法用来区分引用数据类型的,因为所有的引用数据类型都会返回"object"。于是 JavaScript 引入了 Java 中使用的 instanceof,用来判断一个变量是否是某个对象的实例,所以对于引用类型我们使用 instanceof 来进行类型判断。

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

用法:

object instanceof constructor

instanceof 运算符用来检测 constructor.prototype 是否存在于参数 object 的原型链上。

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

暂且不考虑 null 和 undefined(这两个比较特殊),看看控制台输出什么。

可以看到前三个都是以对象字面量创建的基本数据类型,但是却不是所属类的实例,这个就有点怪了。后面三个是引用数据类型,可以得到正确的结果。如果我们通过 new 关键字去创建基本数据类型,你会发现,这时就会输出 true,如下:

具体为什么会这样呢?我们看 MDN 的解释:

var simpleStr = "This is a simple string";
var newStr    = new String("String created with constructor");

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

接下再来说说为什么 null 和 undefined 为什么比较特殊,实际上按理来说,null 的所属类就是 Null,undefined 就是 Undefined,但事实并非如此:控制台输出如下结果:

浏览器压根不认识这两货,直接报错。在第一个例子你可能已经发现了,typeof null 的结果是 object,typeof undefined 的结果是 undefined

尤其是 null,其实这是 js 设计的一个败笔,早期准备更改 null 的类型为 null,由于当时已经有大量网站使用了 null,如果更改,将导致很多网站的逻辑出现漏洞问题,就没有更改过来,于是一直遗留到现在。具体为什么 typeof null = ‘object’,我们前文已经介绍过了,作为学习者,我们只需要记住就好。

3. constructor

constructor 属性返回 Object 的构造函数。

就是返回对象相对应的构造函数。从定义上来说跟 instanceof 不太一致,但效果都是一样的。

如: (a instanceof Array) // a 是否 Array 的实例?true or false

(a.constructor == Array) // a 实例的构造函数是否为 Array? true or false

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

(这里依然抛开 null 和 undefined)乍一看,constructor 似乎完全可以应对基本数据类型和引用数据类型,都能检测出数据类型,事实上并不是如此,来看看为什么:

function Fn() {};
Fn.prototype = new Array();
var f = new Fn();
console.log(f.constructor === Fn);
console.log(f.constructor === Array);

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

看到这里,是不是觉得绝望了。没关系,终极解决办法就是第四种办法,看过 jQuery 源码的人都知道,jQuery 实际上就是采用这个方法进行数据类型检测的。

4. Object.prototype.toString.call()

function type(obj) {
    return Object.prototype.toString.call(obj);
}

console.log(type("aaa"));
console.log(type(1));
console.log(type(true));
console.log(type(null));
console.log(type(undefined));
console.log(type([]));
console.log(type(function () {}));
console.log(type({}));

可以看到,所有的数据类型,这个办法都可以判断出来。那就有人质疑了,假如我把他的原型改动一下呢?如你所愿,我们看一下:

可以看到,依然可以得到正确的结果。

总结

参考

查看全部文章

博文系列目录

交流

各系列文章汇总:https://github.com/yuanyuanbyte/Blog

我是圆圆,一名深耕于前端开发的攻城狮。

weixin