原文地址:https://medium.com/javascript-in-plain-english/how-to-handle-comparison-corner-cases-c96ae9a17d4a原文作者:Alen Vlahovljak译文出自:"掘金翻译计划"(https://github.com/xitu/gold-miner)

“在任何一项足够先进的技术和魔法之间,我们无法做出区分。” — Arthur C. Clarke (?克拉克基本定律三)

在我们开始熟悉 JavaScript 的临界情况之前,我想先区分一下 临界情况(Corner Case) 和 边界情况(Edge Case)

我们可以说 边界情况(Edge Case)是一种仅发生在最小化或最大化参数时的问题。预测这种问题是一项有益之举,因为这些情况可能会被忽视或低估。比如,一台全力运转的 PC 可能会过热,其性能也可能有所折损。

我也想介绍另一种 边界情况(Boundary Case)(这也是一个值得怀疑的问题)。它可能会发生在某个参数逾越了最小化或最大化限制的时候。

那么 临界情况 呢?我并不想给出任何定义,因为在你看过下面的例子之后,你将能自己做到这点。

你将难以置信

如果我问你某些事情能否等于其自己的否定,你的答案会是什么?你肯定会说这是一派胡言,但是:

var arr1 = [];var arr2 = [];

if (arr1 == !arr2) {    console.log("Yes, it's true!");}

if (arr1 != arr2) {    console.log("It's true again!");}

你可能会认为 JS 是一个疯狂的语言,并且这本不应该发生在 JS 这样流行的语言中。这个例子看起来很愚蠢,因为你在实际中绝不会对变量去比较其自身的否定。但这是个帮助你理清思绪的绝佳例子。

你压根不应该比较数组和否定的数组。 不应该以这种方式设计代码。上例就是个绝佳的反例。

在下一个例子中,我将细致地解释发生了什么,所以你会对算法做了什么有个清楚的想象:

var arr1 = [];var arr2 = [];

//1. arr1 == !arr2//2. [] == false //3. "" == false//4. "" == 0//5. 0 == 0 //6. 0 === 0 if (true) console.log("Yes, it's true!");

首先,我将引用 ?文档 中的规则。在以上代码的第 6 行,比较了一个基本类型值和一个非基本类型值。在这种情况下,采用规则 №11 。该算法的结果是一个空字符串。

在下一步中,将一个空字符串和 false 相比较。根据算法,采用规则 №9 。再下一步(第 8 行)则采用规则 №5 。第 5 步成了比较两个数字。因为使用了相等性比较,我们将会调用严格相等性比较算法

最后一步从严格相等性比较中返回了一个 true。第二个例子更实用一点,因为我们使用了不等于(双等于号的否定)- 检查是否强制相等:

var arr1 = [];var arr2 = [];

//1. arr1 != arr2//2. (!(arr1 == arr2))//3. (!(false))if (true) console.log("It's true again!");

鉴于我们比较的是两个非基本类型,这就意味着会执行一个同一性比较。 等同于采用了严格相等性比较。

别惹布尔值

让我们谈谈布尔值极其与抽象相等性的联系。这是你会经常碰到的问题。我们应该看看会发生的临界情况:

var students = [];

if (students) {    console.log("You can see this message!");}

if (students == true) {    console.log("You can't see this message!");}

if (students == false) {    console.log("Working!");}

明确的比较有时反倒会带来不必要的麻烦。 在第二个 if 子句中,我们将数组和布尔值做了比较。你可能认为该操作的结果应当为布尔值 true,但并非如此。严格相等性比较也有同样的效果。

比较一个数组和一个布尔值会引起许多临界情况。在我们看例子之前,我要给你个提示:永远不要对布尔值(true 和 false)使用双等于号。让我们分析下算法是如何工作的:

var students = [];

//** if(students) **//// 1. students // 2. Boolean(students)if (true) console.log("You can see this message!");

//** if(students == true) **//// 1. "" == true// 2. "" == 1// 3. 0 === 1if (false) console.log("You can't see this message!");

//** if(students == false) **//// 1. "" == false// 2. "" == 0// 3. 0 === 0if (true) console.log("Working!");

首个 if 子句是自解释的,所以我不会费时赘述。一如之前的例子,我引用了 ?文档 中的规则。当其中一个被比较的值是非基本类型时,比较数组和布尔值会调用 ?ToPrimitive() 抽象操作(规则 №11)。

之后的三步(译注:第二个 if 子句)直接了当。首先,将一个布尔值转换为一个数字(规则 №9:?ToNumber(true)),接下来字符串变为数字(规则 №5:?ToNumber(“”)),最后一步则是执行一次严格相等性比较。第三个子句同样如此。

强制转换的风险之一就是抽象操作 ToNumber()。我不确定将一个空字符串转换成 0 是否应该。返回 NaN 其实会更好,因为 NaN 表示了一个非法的数字。

推论:无意识的输入总会产生无意识的输出。不必总是显式比较,隐式比较有时比前者更佳。

检查数组值的存在性最好的办法就是明确的检查 .length 以确定其是个字符串还是个数组:

const arr1 = [1, 2, 3];const arr2 = [];

if (arr1) {    console.log("You should see this message!");}

if (arr1.length) {    console.log("Array is not empty!");}

if (arr2) {    console.log("You should not see this message!");}

if (arr2.length) {    console.log("You can't see this message!");}

深层检测更为可靠。如你所见,一个空数组将返回 true (强制转换为布尔值之后)。处理对象是也应采用同样的办法 -- 总是做深层检查。当我们想要确定类型是字符串还是数组时,使用 typeof 操作符(或 Array.isArray() 方法)。

说明

你必须遵守若干准则以避免陷入临界情况的陷阱。随处使用的双等号是把双刃剑。 应谨记当两侧被比较的值是 0、一个空字符串或只包含空格的字符串时,使用双等号是个不好的做法。

下一件应牢记之事是避免对非基本类型使用双等号。唯一能使用它的时机是一致性检查时。 但我也不能说这是 100% 安全的,因为它已经足够接近临界情况,不值得冒险。

?ECMAScript 6 引入了一个新的工具方法 ?Object.is()。借助该方法,我们终于可以在无副作用的情况下执行一致性比较。最后我们可以讲,使用双等号只对基本类型安全,对非基本类型则不安全。

最后但并非最不重要的是要避免对布尔值(true 和 false)使用双等于号。允许隐式的布尔值强制转换(调用 ToBoolean() 抽象操作)会更好。如果不能启用隐式强制转换,又只能对布尔值(true 和 false)使用双等号,那就应该 改为三等号

总结

大多数临界情况都能通过重构代码得以避免。

比较array相等_如何处理JavaScript比较中的临界问题相关推荐

  1. js数组查找最接近_在JavaScript数组中找到最小元素的位置

    在JavaScript数组中找到最小元素的位置 注*  之前有篇文章介绍过数据遍历的性能比较: for in 比for loop慢至少20倍 ,这是另外一篇比较数组查找性能的例子,通过对手工/inde ...

  2. python binascii array('c')_详解Python中的array数组模块相关使用

    初始化array实例化可以提供一个参数来描述允许那种数据类型,还可以有一个初始的数据序列存储在数组中. import array import binascii s = 'This is the ar ...

  3. 对象数组参数_【JavaScript 教程】标准库—Array 对象

    作者 | 阮一峰 1.构造函数 Array是 JavaScript 的原生对象,同时也是一个构造函数,可以用它生成新的数组. var arr = new Array(2);arr.length // ...

  4. javascript字典中添加数组_如何在 JavaScript 中更好地使用数组

    在 freeCodeCamp 社区阅读原文. 本文短小精悍,我保证.在过去的数个月里,我注意到在我审阅的 pull request 中有四个(关于数组使用的)错误经常出现.同时,我自己也会犯这些错误, ...

  5. js 数组去掉括号_如何删除Javascript数组中的方括号?

    我有一个名为value一个数组,当我console.log(value)我得到约30行代码有以下[6.443663, 3.419248]如何删除Javascript数组中的方括号? 的数字变化,因为它 ...

  6. js模板字符串自定义类名_详解JavaScript ES6中的模板字符串

    这篇文章主要介绍了详解JavaScript ES6中的模板字符串,JS的ES6版本带来诸多简洁化方面的重大改进,需要的朋友可以参考下 在 ES6 中引入了一种新的字符串字面量 - 模板字符串,除了使用 ...

  7. react中如何注释代码_学习在您的React / JavaScript代码中发现红旗?

    react中如何注释代码 by Donavon West 由Donavon West 学习在您的React / JavaScript代码中发现红旗? (Learn to spot red flags ...

  8. react中使用构建缓存_通过在React中构建Tic Tac Toe来学习ReasonML

    react中使用构建缓存 3. 7. 2018: UPDATED to ReasonReact v0.4.2 3. 7. 2018:更新为ReasonReact v0.4.2 You may have ...

  9. 如何通过其值获取JavaScript对象中的键?

    本文翻译自:How to get a key in a JavaScript object by its value? I have a quite simple JavaScript object, ...

最新文章

  1. 小型企业的上网行为管理方案
  2. 一周一论文(翻译)——[VLDB 19] Minimizing Cost by Reducing Scaling Operators in Distributed Stream Processing
  3. AI:2020年6月23日北京智源大会演讲分享之智能信息检索与挖掘专题论坛——09:55-10:40刘兵教授《Open-World AI and Continual Learning》
  4. ALV 动态显示列Demo
  5. 美玉待琢——《一本写满评论的艾泽拉斯收藏指南》
  6. 学习思考之《编程之美》.
  7. python中bar是什么意思_Python中下划线的变量是什么个意思
  8. MongoDB复制集安全认证
  9. 小米6android版本更新,钉子户小米6的新生,换电池、背盖,升级android11
  10. 【读书笔记】《王道论坛计算机考研机试指南》第二章
  11. JSP内置对象-out对象
  12. Latex排版—(1)基础排版
  13. cracking the pm interview_2020泰晤士报THE世界大学排名发布!如何凭艺术冲进大U名校?...
  14. Matlab/Simulink 自动代码生成 基于模型设计学习教程(1)---- 环境配置
  15. ResponseBodyAdvice的使用
  16. 批量录入快递地址解决方案
  17. pthon缺陷检测(机器视觉)
  18. C语言编程学习:写的秒速计算四则混合运算项目
  19. 必考题系列--十种常见的运行时异常
  20. Mysql错误代码1045

热门文章

  1. 【转】android是32-bit系统还是64-bit系统
  2. 安卓模拟器BlueStacks 安装使用教程(图解)
  3. MATLAB常见语法错误分析及解决办法
  4. 【CF464E】The Classic Problem(主席树+最短路)
  5. javascript移动端 电子书 翻页效果
  6. Windows 搭建ASP.NET Boilerplate项目开发环境
  7. Linux系统日志分析与管理(14)
  8. SSH整合框架+mysql简单的实现
  9. BestCoder 2nd Anniversary
  10. Equinox P2的学习