JavaScript专题(六)类型检测

JavaScript专题之数据类型检测的那些事

目录

前言

《JavaScript的数据类型》中我们也提到过简单的类型检测问题。

作为前端的同学,我们应该都知道可以使用typeof和instanceof在运行时判断JavaScript数据的类型,那么他们都是怎么判断的呢?一千个人会不会写出来一千个判断方法?

本文会从通用的typeof、到专攻对象的instanceof,再到isNull、isNumber、isString等方法,来讨论如何判断数据类型,一起加油~

在这里插入图片描述

一、typeof

typeof:操作符返回一个字符串,表示未经计算的操作数的类型。

我们都知道,在 ES6 前,JavaScript 共六种数据类型,分别是:

  1. Undefined
  2. Null
  3. Boolean
  4. Number
  5. String
  6. Object

然而当我们使用 typeof 对这些数据类型的值进行操作的时候,返回的结果却不是一一对应,分别是:

  1. Undefined
  2. object – ***
  3. Boolean
  4. Number
  5. String
  6. Object

有一些意外,typeof null => 'object'typeof function(){} => 'function'

所以在大多数情况下我们可以使用typeof来检测基本数据类型,但是,检测得到的Object后,却无法区分是哪一种Object:

typeof [] === 'object'; //true
typeof {} === 'object'; //true
typeof null === 'object'; //true

总结

👉🏻 在检测Js的原始类型时,除了typeof null返回object之外,其他的都返回对应类型名的小写字母。

二、instanceof

我们判断对象类型的时候,可以使用instanceof:

如果对原型及原型链不太熟悉的同学不妨看看这篇文章从原型到原型链

定义

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

实例

const arr = [];
const obj = {};

console.log(arr instanceof Array);   // true
console.log(arr instanceof Object);  // true
console.log(obj instanceof Array);   // false
console.log(obj instanceof Object);  // true

💡 注意instanceof是能匹配类型的父类的,所以arr instanceof Array和arr instanceof Object都是true,因为Object是Array的父类。

满足class extends原型链规则的父子类关系的对象都能被匹配:

class

class Base {}

class Current extends Base {}

const obj = new Current();

console.log(obj instanceof Current); // true
console.log(obj instanceof Base); // true

原型链

function Foo() {}

function Bar() {}

Bar.prototype = new Foo();

const obj = new Bar();

console.log(obj instanceof Bar); // true
console.log(obj instanceof Foo); // true

⚠️ 注意如果我们修改obj的原型链能改变instanceof的结果:

function Other() {}

obj.__proto__ = new Other();

console.log(obj instanceof Other); // true
console.log(obj instanceof Foo); // false

总结

👉🏻 instanceof借助了原型链来判断的实际上,只要一个类型Type的prototype在一个对象obj的原型链上,那么obj instanceof Type就是true,否则就是false。

三、constructor

有时候我们不希望匹配父类型,只希望匹配当前类型,那么我们可以用constructor来判断:

如果对原型及原型链不太熟悉的同学不妨看看这篇文章从原型到原型链

定义

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

实例

const arr = [];

console.log(arr.constructor === Array); // true
console.log(arr.constructor === Object); // false

👉🏻 对象的constructor会返回它的类型,而类型在定义的时候,会创建一个name只读属性,值为类型的名字。

class Foo {

}
console.log(Foo.name); // Foo

const foo = new Foo();
console.log(foo.constructor === Foo); // true
console.log(foo.constructor.name === 'Foo'); // true

疑问

  • constructor.name 一定就是正确的吗?
  • 我们可以修改它吗?

四、stringTag是什么?

4.1 stringTag——类型标签

如果你看过一些库的早期实现,你会发现使用Object.prototype.toString来做类型判断的方式,他们会数据类型的字符串标志,被称作stringTag

4.2 Object.prototype.toString

定义

toString()方法返回一个表示该对象的字符串。

每个对象都有一个 toString() 方法,当该对象被表示为一个文本值时,默认情况下,toString() 方法被每个 Object 对象继承。

⚠️ 如果此方法在自定义对象中未被覆盖,toString() 返回 “[object type]”,其中 type 是对象的类型。以下代码说明了这一点:

实例

比如这是requirejs里面的代码片段。

var ostring = Object.prototype.toString;
function isArray(it) {
  return ostring.call(it) === '[object Array]';
}

toString时都做了什么?

这里直接将冴羽大大的总结搬了过来:

When the toString method is called, the following steps are taken:

  1. If the this value is undefined, return “[object Undefined]”.
  2. If the this value is null, return “[object Null]”.
  3. Let O be the result of calling ToObject passing the this value as the argument.
  4. Let class be the value of the [[Class]] internal property of O.
  5. Return the String value that is the result of concatenating the three Strings "[object ", class, and “]”.

当 toString 方法被调用的时候,下面的步骤会被执行:

  1. 如果 this 值是 undefined,就返回 [object Undefined]
  2. 如果 this 的值是 null,就返回 [object Null]
  3. 让 O 成为 ToObject(this) 的结果
  4. 让 class 成为 O 的内部属性 [[Class]] 的值
  5. 最后返回由 "[object " 和 class 和 “]” 三个部分组成的字符串

注意

有几点我们需要注意:

  • toString无法区分原始类型及其构造对象;
    • 我们认为Number、Boolean这种类型在被构造器构造出来后的类型应该是对象
    • 但toString都会返回[object number]等原始类型;
  • toString方法是可以自定义的;

在这里插入图片描述

五、实现几个数据检测的方法

好了看了几款常用的类型判断方法后,我们可不可以实现自己的类型判断工具?就利用上述提到的一个或多个方法。我们自己动手丰衣足食~

5.1 isObject

注意,我们认为null不是一个对象,它就是null~

function isObject(value) {
    const type = typeof value;
    return value != null && (type === 'object' || type === 'function');
}
5.2 isNull
function isNull(value) {
    return value === null;
}
5.3 isFunction
function isFunction(value) {
    return typeof value === 'function';
}
5.4 isArray
var isArray = Array.isArray || function( value ) {
    return type(value) === "array";
}
5.5 stringTag
const toString = Object.prototype.toString;

function getTag(value) {
    // if (value === null) return '[object Null]';
    // if (value == null) return '[object Undefined]'
    if (value == null) {
        return value === undefined ? '[object Undefined]' : '[object Null]'
    }
    return toString.call(value)
}

好了到最后,大家平时对类型检测的态度是什么样的呢?

写在最后

JavaScript系列:

  1. 《JavaScript内功进阶系列》(已完结)
  2. 《JavaScript专项系列》(持续更新)

关于我

  • 花名:余光(沉迷JS,虚心学习中)
  • WX:j565017805

其他沉淀

如果您看到了最后,对文章有任何建议,都可以在评论区留言

这是文章所在GitHub仓库的传送门,如果真的对您有所帮助,希望可以点个star,这是对我最大的鼓励 ~

已标记关键词 清除标记
相关推荐
课程简介: 历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:
©️2020 CSDN 皮肤主题: 博客之星2020 设计师:CY__ 返回首页