资讯专栏INFORMATION COLUMN

解析JavaScript判断两个值相等的方法

3403771864 / 540人阅读

  本篇文章主要是讲述在JavaScript中判断两个值相等,不要认为很简单,要注意的是在JavaScript中存在4种不同的相等逻辑。

  ECMAScript 是 JavaScript 的语言规范,在ECMAScript 规范中存在四种相等算法,如下图所示:

1.png

  上图中每个依次写下来,很多前端应该熟悉严格相等和非严格相等,但对于同值零和同值却不熟悉,现在就依次下面四种方法。

  同值

  同值零

  非严格相等

  严格相等

  非严格相等

  非严格相等使用两个等号,这个双等就很熟悉,非严格相等表示语义相等,不要求类型一样,非严格相等在比较前会先将比较参数类型转换为一致,要再次进行比较,代码示例如下:

  1 == 1; // true
  1 == '1'; // true 类型不同,不影响比较结果

  非严格相等有非常复杂的转换规则,非常难以记忆,社区中有人将上面的规则总结成了图片,一图胜千言,如下图所示:

2.jpg

  这么多,我们要先进行总结,就是如下三条规则:

  Undefined 只和 Null 相等

  和 Number 比较时,另一个值会自动转换为 Number

  和 Boolean 比较时,另一个值会转换为 Number

  如果值为对象,会使用内部的 ToPrimitive 转换,可以通过自定义 Symbol.toPrimitive 改变返回值,需要注意的是在相等的判断中 Symbol.toPrimitive 接受的 hint 参数都是 default。 

 const obj = {
  [Symbol.toPrimitive](hint) {
  console.log(hint);
  if (hint == 'number') {
  return 1;
  }
  if (hint == 'string') {
  return 'yan';
  }
  return true;
  },
  };
  console.log(obj == 1); // obj 返回 true
  console.log(obj == '1'); // obj 返回 true
  console.log(obj == true); // obj 返回 true

  其实非严格相等并不可以带来很多便利,换个角度,可以通过隐式的自动转换,简化了部分场景的工作,比如 Number 和 String 的自动转换,简化了前端从表单,url 参数中获取值的比较问题,但自动转换带来的问题比便利还多。

  隐式转换的规则,这个在很多情况下就不适用,对于现在的观点并不建议是引用,作者建议只在判断 undefined 和 null 的场景下可以使用非严格相等。

  严格相等

  严格相等是另一种比较算法,其和非严格想等的区别是不会进行类型转换,类型不一致时直接返回 false,严格相等对应===操作符,因为使用三个等号,也被称作三等或者全等,严格相等举例:

  1 === 1; // true
  1 === '1'; // false 类型不同,影响比较结果

  重点:在不同类型值判断规则下图所示,与前面的非严格相等对比,总的来说严格相等更符合直觉。

3.jpg

  严格相等解决了非严格相等中隐式转换带来的问题,但也丢失了隐式转换带来的便利,主要是可能对于类型不一致的情况,比如从表单中获取的值都是字符串,其实保守的做法就是在比较前手动类型转换,代码示例如下:

  1 === Number('1'); // true 手动类型转换,类型防御

  严格相等几乎总是正确的,可有例外,比如 NaN 和正负 0 的问题。

  Number 类型有个特殊的值 NaN,用来表示计算错误的情概况,比较常见是非 Number 类型和 Number 类型计算时,会得到 NaN 值,代码示例如下所示,这是从表单和接口请求获取数据时很容易出现的问题。

  const a = 0 / 0; // NaN
  const b = 'a' / 1;
  const c = undefined + 1; // NaN

  在严格相等中,NaN 是不等于自己的,NaN 是(x !== x) 成立的唯一情况,这种状况下是可以判断 NaN 的,可以使用 isNaN 进行判断,ECMAScript 2015 引入了新的 Number.isNaN,和 isNaN 的区别是不会对传入的参数做类型转换,建议使用语义更清晰的 Number.isNaN,但是要注意兼容性问题,判断 NaN 代码示例如下:

  NaN === NaN; // false
  isNaN(NaN); // true
  Number.isNaN(NaN); // true
  isNaN('aaa'); // true 自动转换类型 'aaa'转换为Number为NaN
  Number.isNaN('aaa'); // false 不进行转换,类型不为Number,直接返回false

  严格相等另一个例外情况是,无法区分+0 和-0,代码示例如下,在一些数学计算场景中是要区分语义的。

  +0 === -0; // true

  JavaScript 中很多系统函数都使用严格相等,比如数组的 indexOf,lastIndexOf 和 switch-case 等,需要注意,这些对于 NaN 无法返回正确结果,代码示例如下:

  [NaN].indexOf(NaN); // -1 数组中其实存在NaN
  [NaN].lastIndexOf(NaN); // -1

  同值零

  同值零是另一种相等算法,名字来源于规范的直译,规范中叫做 SameValueZero,同值零和严格相等功能一样,除了处理 NaN 的方式,同值零认为 NaN 和 NaN 相等,这在判断 NaN 是否在集合中的语义下是非常合理的。

  ECMAScript 2016 引入的 includes 使用此算法,此外 Map 的键去重和 Set 的值去重,使用此算法,代码示例如下:

  [NaN].incdudes(NaN); // true 注意和indexOf的区别,incdudes的语义更合理
  new Set([NaN, NaN]); // [NaN] set中只会有个一个NaN,如果 NaN !== NaN的话,应该是[NaN, NaN]
  new Map([
  [NaN, 1],
  [NaN, 2],
  ]); // {NaN => 2} 如果 NaN !== NaN的话,应该是 {NaN => 1, NaN => 2}

  同值

  同值是最后一种相等算法,其和同值零类似,但认为 +0 不等于 -0,ECMAScript 2015 带来的 Object.is 使用同值算法,代码示例如下:

  Object.is(NaN, NaN); // true
  Object.is(+0, -0); // false ???? 注意这里

  同值算法的使用场景是,确定两个值是否在任何情况下功能上是相同的,比较不常用,defineProperty 使用此算法确认键是否存在,例如,将存在的只读属性值-0 修改为+0 时会报错,如果设置为同样的-0 将执行正常,代码示例如下: 

 function test() {
  'use strict'; // 需要开启严格模式
  var a = {};
  Object.defineProperty(a, 'a1', {
  value: -0,
  writable: false,
  configurable: false,
  enumerable: false,
  });
  Object.defineProperty(a, 'a1', {
  value: -0,
  }); // 正常执行
  Object.defineProperty(a, 'a1', {
  value: 0,
  }); // Uncaught TypeError: Cannot redefine property: a1
  }
  test();

  对于数组判断是否存在的场景,如果想区分+0 和-0,可以使用 ECMAScript 2015 引入的 find 方法,自行控制判断逻辑,代码示例如下:

  [0].includes(-0); // 不能区分-0
  [0].find((val) => Object.is(val, -0)); // 能区分+0和-0

  总结

  最后来对比下四种算法的区别,区别如下表所示:


隐式转换NaN 和 NaN+0 和 -0
非严格相等(==)falsetrue
严格相等(===)falsetrue
同值零(includes 等)truetrue
同值(Object.is)truefalse

    JavaScript判断相等值内容讲述完了,希望大家好好学习更多知识。



文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/128374.html

相关文章

  • 【前端工程师手册】说清楚JavaScript相等判断

    摘要:如果没有传入的话如果是类型,则取否则,取这个方法大致和一样,除了以下返回返回参考知乎中和区别是什么全面解析中的数据类型与类型转换规范 有哪些判断相等性的方法 JavaScript现在提供了三种方法来判断相等性: ===,三个等号即严格相等 ==,两个等号即宽松相等 Object.is(),ES6中用来判断相等的方法 判断相等性的细节 ===(严格相等) 被比较的两个数不会进行类型转...

    crossoverJie 评论0 收藏0
  • JavaScript专题系列文章

    摘要:专题系列共计篇,主要研究日常开发中一些功能点的实现,比如防抖节流去重类型判断拷贝最值扁平柯里递归乱序排序等,特点是研究专题之函数组合专题系列第十六篇,讲解函数组合,并且使用柯里化和函数组合实现模式需求我们需要写一个函数,输入,返回。 JavaScript 专题之从零实现 jQuery 的 extend JavaScritp 专题系列第七篇,讲解如何从零实现一个 jQuery 的 ext...

    Maxiye 评论0 收藏0
  • Effective JavaScript读书笔记(一)

    摘要:如果为假值,不传或者传入,函数都会返回但是,传入这个值是完全有可能的,所以这种判断形势是不正确的或者使用来判断也可以原始类型优于封装类型对象拥有六个原始值基本类型布尔值,数字,字符串,,和对象。 作为一个前端新人,多读书读好书,夯实基础是十分重要的,正如盖楼房一样,底层稳固了,才能越垒越高。从开始学习到现在,基础的读了红宝书《JavaScript高级程序设计》,犀牛书《JavaScri...

    zhoutao 评论0 收藏0
  • JavaScript“黑话”

    摘要:数值表示法科学计数法是一种数学术语,将一个数表示为乘以的次方,如光速万公里每秒,在计算中通常将米做单位,则记为,而在中我们可使用科学计数法表示。以下情况会自动将数值转为科学计数法表示小数点前的数字多于位。 showImg(https://segmentfault.com/img/bVbhNqT?w=1024&h=683); 因为球是圆的,所以不论发生什么都有可能,对这点我是深信不疑的,...

    fjcgreat 评论0 收藏0
  • 深入理解JavaScript类型转换

    摘要:等同于等同于其他类型和布尔类型之间的比较如果是布尔类型,则返回的结果。 showImg(https://segmentfault.com/img/bVburFq?w=796&h=398); 前言 JavaScript作为一门弱类型语言,我们在每天的编写代码过程中,无时无刻不在应用着值类型转换,但是很多时候我们只是在单纯的写,并不曾停下脚步去探寻过值类型转换的内部转换规则,最近通过阅读你...

    W4n9Hu1 评论0 收藏0

发表评论

0条评论

3403771864

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<