再也不用担心变量类型错误!学会JS中如何轻松检查变量类型

这篇具有很好参考价值的文章主要介绍了再也不用担心变量类型错误!学会JS中如何轻松检查变量类型。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

今天要分享的问题就是:如何在JS中检查一个变量的类型?

先上结论:
如果判断的是基本数据类型或JavaScript内置对象,使用toString;如果要判断的是自定义类型,请使用instanceof。

在 ECMAScript 规范中,共定义了 7 种数据类型,分为 基本类型引用类型 两大类。

基本类型 也称为简单类型,按值访问。

引用类型 也称为复杂类型,按址访问。
JavaScript内置了一些引用类型,如图所示:

JavaScript的变量是松散类型。虽然这使得提供类型信息的方式更加灵活了,但也容易误用。

下面来分析常见的四种JavaScript类型检查方法:typeof, instanceof, constructor, toString

typeof

typeof是一个操作符,其右侧跟一个一元表达式,并返回这个表达式的数据类型。

它返回的结果用该类型的字符串(全小写字母)形式表示。返回值有7种取值:numberbooleansymbolstringundefinedobjectfunction

typeof 3; // number 有效
typeof true; //boolean 有效
typeof Symbol(); // symbol 有效
typeof ''; // string 有效
typeof undefined; //undefined 有效
typeof null; //object 无效
typeof [] ; //object 无效
typeof new Function(); // function 有效
typeof new Date(); //object 无效
typeof new RegExp(); //object 无效

有些时候,typeof操作符会返回一些令人迷惑但技术上却正确的值:

  • 对于基本类型 ,除 null 以外,均可以返回正确的结果。
  • 对于引用类型 ,除 function 以外,一律返回object类型。
  • 对于null ,返回object类型。这是一个知名的bug。由于影响范围越来越大,就没有修复了。
  • 对于function 函数,返回 function 类型。从技术角度讲,函数在ECMAScript中是对象,不是一种数据类型。然而,函数也确实有一些特殊的属性,因此通过typeof操作符来区分函数和其他对象是有必要的。

由上可以得出:
typeof引用类型 操作的返回值不是我们想要的结果。

instanceof

instanceof是用来判断 A 是否为 B 的实例的。它的表达式为:A instanceof B

如果 A 是 B 的实例,则返回 true,否则返回 false。 在这里需要特别注意的是:instanceof断规则是某个对象的原型链是否包含某个构造函数的prototype属性

let arr = [];
arr instanceof Array; // true
arr instanceof Object; // true

看看arr原型链简图:

arr的 __proto__ 直接指向Array.prototype,间接指向 Object.prototype,所以按照 instanceof 的判断规则,[] 就是Array的实例,也是Object的实例。instanceof返回值都是true

依此类推,RegExp, Object, Function也会形成一条对应的原型链 。

/abc/ instanceof RegExp // true
({}) instanceof Object // true
(function(){}) instanceof Function // true

instanceof是通过原型链来检查类型的,所以适用于任何"object"的类型检查。自定义的类型同样满足。

// 比如直接原型关系
function Fruit(){ }
(new Fruit) instanceof Fruit     // true

// 原型链上的间接原型
function Apple(){}
Apple.prototype = new Fruit
(new Apple) instanceof Fruit         // true

注意instanceof基本数据类型 不起作用,因为基本数据类型没有原型链。

3 instanceof Number // false
true instanceof Boolean // false
'abc' instanceof String // false
null instanceof String  // always false
undefined instanceof String  // always false

但你可以这样:

new Number(3) instanceof Number // true
new Boolean(true) instanceof Boolean // true
new String('abc') instanceof String // true

但这时你已经知道数据类型了,类型检查已经没有意义了。

使用constructor属性

constructor 属性返回一个指向创建了该对象原型的函数引用。需要注意的是,该属性的值是那个函数本身。例如:

function Fruit(){}
var a = new Fruit
a.constructor === Fruit    // true

constructor不适合用来判断变量类型。

  • 其一,它是一个属性,非常容易被伪造:
var a = new Fruit
a.constructor === Array
a.constructor === Fruit    // false
  • 其二,constructor指向的是最初创建当前对象的函数,是原型链最上层的那个方法:
function Apple(){}
Apple.prototype = new Fruit

function BadApple(){}
BadApple.prototype = new Apple

(new BadApple).constructor === Fruit   // true
Fruit.constructor === Function       // true

与instanceof类似,constructor只能用于检测引用对象,对基本数据类型无能为力。

与instanceof不同的是,在访问基本数据类型的属性时,JavaScript会自动调用其构造函数来生成一个对象。例如:

(3).constructor === Number // true
true.constructor === Boolean // true
'abc'.constructor === String // true
// 相当于
(new Number(3)).constructor === Number
(new Boolean(true)).constructor === Boolean
(new String('abc')).constructor === String

这种将一个值类型转换为对象引用类型的机制在其他语言中也存在,称为装箱

但在基本数据类型中,nullundefined调用constructor会抛出TypeError异常。

null.constructor         // TypeError!
undefined.constructor    // TypeError!

因为null是JavaScript原型链的起点,undefined是无效对象,都没有构造函数,也就不存在constructor属性。

instanceof跨窗口问题

我们知道Javascript是运行在宿主环境下的,而每个宿主环境会提供一套ECMA标准的内置对象,以及宿主对象(如window, document),一个新的窗口即是一个新的宿主环境。 不同窗口下的内置对象是不同的实例,拥有不同的内存地址。

instanceofconstructor都是通过比较两个Function是否相等来进行类型判断的。 此时显然会出问题,例如:

var iframe = document.createElement('iframe');
var iWindow = iframe.contentWindow;
document.body.appendChild(iframe);

iWindow.Array === Array         // false
// 相当于
iWindow.Array === window.Array  // false

因此iWindow中的数组arr原型链上是没有window.Array的。请看:

iWindow.document.write('<script> var arr = [1, 2]</script>');
iWindow.arr instanceof Array            // false
iWindow.arr instanceof iWindow.Array    // true

使用toString方法

使用toString方法是最为可靠的类型检测手段,它会将当前对象类型转换为字符串并输出。

toString属性定义在Object.prototype上,因而所有对象都拥有toString方法。但Array, Date等对象会重写从Object.prototype继承来的toString,所以最好用Object.prototype.toString来检测类型。

toString = Object.prototype.toString;

toString.call(new Date);  // [object Date]
toString.call(new String);// [object String]
toString.call(Math);      // [object Math]
toString.call(3);         // [object Number]
toString.call([]);        // [object Array]
toString.call({});        // [object Object]

// Since JavaScript 1.8.5
toString.call(undefined); // [object Undefined]
toString.call(null);      // [object Null]

采用toString也不是完美的,它无法检测用户自定义类型。因为Object.prototype是不知道用户会创造什么类型的,它只能检测ECMA标准中的那些内置类型。

toString.call(new Fruit) // [object Object]

因为返回值是字符串,也避免了跨窗口问题。当然IE弹窗中还是有Bug,不必管它了。 现在多少人还在用IE?多少人还在用弹窗?

和Object.prototype.toString类似地,Function.prototype.toString也有类似功能,不过它的this只能是Function,其他类型(例如基本数据类型)都会抛出异常。

其他

有时Duck Typing的类型推断方式也非常可行,貌似已经成为了前端的惯例。比如jQuery是这样判断一个Window的:

isWindow: function(obj){
    return obj && typeof obj === 'object' && "setInterval" in obj;
}

总结

  • typeof只能检测基本数据类型,对于null还有Bug;
  • instanceof适用于检测对象,它是基于原型链运作的;
  • constructor指向的是最初创建者,而且容易伪造,不适合做类型判断;
  • toString适用于ECMA内置JavaScript类型(包括基本数据类型和内置对象)的判断;
  • 引用类型 检查都有跨窗口问题,比如instanceof和constructor。

总之,如果你要判断的是基本数据类型或JavaScript内置对象,使用toString; 如果要判断的是自定义类型,请使用instanceof。文章来源地址https://www.toymoban.com/news/detail-481442.html

到了这里,关于再也不用担心变量类型错误!学会JS中如何轻松检查变量类型的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 项目代码混淆,实战来了,再也不用担心代码泄露了!

    简单就是把代码跑一哈,然后我们的代码 .java文件 就被编译成了 .class 文件 就是针对编译生成的 jar/war 包 里面的 .class 文件 逆向还原回来,可以看到你的代码写的啥。 比较常用的反编译工具 JD-GUI ,直接把编译好的jar丢进去,大部分都能反编译看到源码: 那如果不想给别人反

    2023年04月26日
    浏览(32)
  • 学会这几招,再也不担心电脑被黑客入侵

    人们常说Mac不能被黑客入侵,但事实并非如此。虽然Mac可能不像Windows PC频繁的受到攻击,但黑客成功入侵Mac的例子有很多,从虚假程序到利用漏洞。 Windows PC比MacBook更频繁成为目标的重要原因之一是市场占用份额。截至 2022 年,Windows 在桌面市场的操作系统中的全球市场份额

    2024年01月22日
    浏览(38)
  • 使用ChatGPT+MindShow一键生成PPT,以后再也不用担心制作PPT啦

    💖 作者简介:大家好,我是阿牛,全栈领域优质创作者。😜 📝 个人主页:馆主阿牛🔥 🎉 支持我:点赞👍+收藏⭐️+留言📝 💬格言:迄今所有人生都大写着失败,但不妨碍我继续向前!🔥 我们经常会有制作ppt的需求,尤其大学里面的小组报告,什么班会团课之类的,

    2023年04月23日
    浏览(40)
  • Z-Libary最新地址检测,再也不用担心找不到ZLibary了

    Z-Library。世界上最大的数字图书馆。 如果你知道了一本书的书名,那在Z-Library上基本上都可以找到进行下载, Z-Library 有很多入口,分为官方和民间镜像。官方自己做了个跳转站点,会自动寻找官方可用网站。一般用官方入口即可,但也存在所有官方入口均封闭情况,此时建议

    2024年02月08日
    浏览(28)
  • 解析不同种类的StableDiffusion模型Models,再也不用担心该用什么了

    Stable Diffusion是一个基于Latent Diffusion Models(潜在扩散模型,LDMs)的文图生成(text-to-image)模型。具体来说,Stable Diffusion在 LAION-5B 的一个子集上训练了一个Latent Diffusion Models,该模型专门用于文图生成。Latent Diffusion Models通过在一个潜在表示空间中迭代“去噪”数据来生成图

    2023年04月19日
    浏览(31)
  • C语言——程序环境和预处理(再也不用担心会忘记预处理的知识)

    先简单了解一下程序环境,然后详细总结翻译环境里的编译和链接,然后在总结编译预处理。 在 ANSI C 的任何一种实现中,存在两个不同的环境 翻译环境:这个环境中源代码被转换为可执行的机器指令。 执行环境:执行二进制代码。 计算机如何执行二进制指令? 我们写的C语

    2024年02月09日
    浏览(43)
  • 初识Linux(上),看了这篇文章,妈妈再也不用担心我Linux找不到门了。

    “我会定期分享我的学习经验,也欢迎大家留言和交流,让我们共同学习和进步!感谢大家的支持,让我们一起开启这段充满技术乐趣的旅程吧!” 系列文章 初识Linux(上).妈妈再也不用担心我Linux找不到门了。 初识Linux(中).妈妈再也不用担心我Linux找不到门了。 初识Linux(下

    2024年02月05日
    浏览(31)
  • 有了它,你再也不用担心作曲啦!智能作曲新纪元:Suno AI引领音乐创作的未来之路!

    Suno AI:赋予音乐无限想象,你的个人智能作曲家,让灵感瞬间跃动成曲! - 精选真开源,释放新价值。 Suno AI,这一开创性的人工智能音乐创作平台,是由全球顶尖的科技创新企业Anthropic公司以及相关前沿科研团队深度研发并精心打磨的结晶。该解决方案以革新性的视角,

    2024年04月17日
    浏览(42)
  • List 转换 Map,三大类,7种方法-非常详细,学会再也不担心这类问题

    数据准备: 1.pojo对象 2.personList 1.基本用法 2.转换过程中会存在的两个问题 Map的value不是Person对象,而是Person的成员变量。 1)原list有重复的key 数据准备:personList 策略一 重复时 用后面的value 覆盖前面的value 策略二 将前面的value 和后面的value拼接起来 策略三 重复时将重复

    2024年04月25日
    浏览(24)
  • Selenium教程05:使用webdriver-manager自动下载浏览器驱动,再也不用担心driver版本的问题了

    WebDriverManager是一个用于管理Web驱动程序的工具,主要用于自动化测试领域。在进行 Selenium 测试时,需要一个与浏览器相匹配的 Web 驱动程序,以便控制和操作浏览器。WebDriverManager可以自动下载和管理浏览器驱动程序,会自动检测本地系统中安装的浏览器,并下载对应的浏览

    2024年01月17日
    浏览(53)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包