Appearance
平等的价值
想象一下,参加一个只有几种面具的狂欢节。一群穿着相同服装的人会在房间里开玩笑、跳舞、走动。这会让人困惑!你可能会和两个人交谈,却没有意识到你实际上是在和同一个人交谈两次。或者你可能认为你在和一个人说话,但实际上,你在和两个不同的人说话!
如果您在JavaScript中没有一个明确的平等的心智模型,那么每天都像狂欢节一样——而且不是以一种好的方式。你无法确定你处理的是相同的值,还是两个不同的值。因此,您经常会犯错误——比如更改一个您不打算更改的值。 幸运的是,我们已经完成了在JavaScript中建立平等概念的大部分工作。它以一种非常自然的方式符合我们的心智模式。
Kinds of Equality
在JavaScript中,有几种相等,如果你已经写过JS了,你应该对下面的几种相等不陌生
- Strict Equality:
a === b
(triple equals). - Loose Equality:
a == b
(double equals). - Same Value Equality:
Object.is(a, b)
.
Object.is(a,b)
在JavaScript中,Object.is(a,b)
告诉我们a和b是否有相同的值
console.log(Object.is(2, 2)); // true
console.log(Object.is({}, {})); // false
这叫做相同的值相等。
尽管方法名是Object.is
并不特定于对象。它可以比较任意两个值,不管它们是否是对象!
检查一下你的直觉🥳
let dwarves = 7;
let continents = '7';
let worldWonders = 3 + 4;
提示一下:这段代码的心智模型是如下的
现在,尝试告诉我一下下面代码的答案
console.log(Object.is(dwarves, continents)); // ?
console.log(Object.is(continents, worldWonders)); // ?
console.log(Object.is(worldWonders, dwarves)); // ?
下面是答案👇:
Object.is(dwarves, continents)
是false
因为dwarves
和continents
指向不同的值.Object.is(continents, worldWonders)
是false
因为continents
和worldWonders
指向不同的值.Object.is(worldWonders, dwarves)
是true
因为worldWonders
和dwarves
指向相同的值.
但是对象呢? 到这里,您可能要担心对象了。您可能听说过等式对对象无效,或者它比较“引用”。如果你有这样的直觉,那就暂时把它们放在一边。 相反,请看下面的代码片段
let banana = {};
let cherry = banana;
let chocolate = cherry;
cherry = {};
记住,{}总是表示“创建一个新的对象值”。另外,请记住=的意思是“将左侧的导线指向右侧的值”。
现在再来解答一下下面的问题?👇
console.log(Object.is(banana, cherry)); // ?
console.log(Object.is(cherry, chocolate)); // ?
console.log(Object.is(chocolate, banana)); // ?
Object.is(banana, cherry)
是false
因为banana
和cherry
指向不同的值.Object.is(cherry, chocolate)
是false
因为cherry
和chocolate
指向不同的值.Object.is(chocolate, banana)
是true
因为chocolate
和banana
指向相同的值.
正如您所看到的,我们不需要任何额外的概念来解释相同的值相等性如何适用于对象。它是通过我们的思维模式自然产生的。这就是我所知道的一切!
严格相等
您以前可能使用过严格相等操作符
console.log(2 === 2); // true
console.log({} === {}); // false
同值平等与严格平等
Object.is
和===
有什么区别呢?
- Object.is和我们心智模型中的值相等保持一致
- 严格相同绝大部门情况下也和心智模型一致,但是也有一些特殊情况
这两种不寻常的情况都涉及我们过去讨论过的“特殊数字”:
NaN === NaN
是false
,尽管它们的值相同。-0 === 0
并且0 === -0
是true
,尽管它们是不同的值。
第一个特殊的例子: NaN
NaN
是一个特殊的Number ,当我们做无效的数学时就会出现 0 / 0
:
let width = 0 / 0; // NaN
进一步的计算 NaN
也将会给你一个 NaN
:
let height = width * 2; // NaN
您可能不会故意这样做,但如果您的数据或计算存在缺陷,就会发生这种情况.
记住 NaN === NaN
永远都是 false
:
console.log(width === height); // false
然而, NaN
和 NaN
是同一个值:
console.log(Object.is(width, height)); // true
这很令人困惑。 NaN === NaN 为假的原因很大程度上是历史原因,所以我建议接受它作为生活的事实。如果您尝试编写一些检查值是否为 NaN 的代码(例如,打印警告),您可能会遇到这种情况。
function resizeImage(size) {
if (size === NaN) {
// 这将永远不会被记录:检查永远是假的!
console.log('Something is wrong.');
}
// ...
}
相反,这里有一些方法(它们都有效!)来检查size是否为NaN:
Number.isNaN(size)
Object.is(size, NaN)
size !== size
最后一个可能特别令人惊讶。给它一些时间。如果您没有看到它是如何检测NaN的,请尝试重新阅读这一节并再次思考它。
size !== size有效,因为NaN === NaN是假的,正如我们已经知道的。所以反过来(NaN !== NaN)一定是真的。 因为NaN是唯一不是严格等于自身的值,size !== size只能表示size是NaN。
一个简单的历史: https://stackoverflow.com/questions/1565164/what-is-the-rationale-for-all-comparisons-returning-false-for-ieee754-nan-values/1573715#1573715 。确保开发人员能够以这种方式检测 NaN 是使 NaN === NaN 返回 false 的最初原因之一!这是在JavaScript出现之前就决定的
第二个特殊的例子: -0
在普通数学中,没有“负0”这样的概念,但在浮点数学中却存在实际原因。这里有一个有趣的事实。
Both 0 === -0
and -0 === 0
are always true
:
let width = 0; // 0
let height = -width; // -0
console.log(width === height); // true
然而, 0
和 -0
不是同一个值:
console.log(Object.is(width, height)); // false
编码练习
现在您知道了Object.is和=== 是如何工作的了,我有一个小的编码练习给你。你不需要完成它,但它是一个有趣的难题
写一个函数strictEquals(a, b),返回与a === b相同的值。你的实现不能使用===或!==操作符。
下面是我的答案 🐥
function strictEquals(a, b) {
if (Object.is(a, b)) {
if (Object.is(a, NaN) || Object.is(b, NaN)) {
return false
} else {
return true
}
} else {
if ((Object.is(a, -0) && Object.is(b, 0)) ||
Object.is(b, -0) && Object.is(a, 0)) {
return true
} else {
return false
}
}
} // sudongyuer🐟
听到这些特殊的数字和他们的行为可能会让人不知所措。不要过分强调这些特殊情况! 它们并不常见。既然你知道它们的存在,你就会在实践中认识到它们。在大多数情况下,我们可以相信Object.is (a, b)
和 a === b
。
宽松的平等
松散等号(双等号)是JavaScript的梦魇。下面是几个让你起鸡皮疙瘩的例子:
console.log([[]] == ''); // true
console.log(true == [1]); // true
console.log(false == [0]); // true
松散相等(也称为“抽象相等”)的规则是晦涩难懂的。许多编码标准完全禁止在代码中使用==和!=。 尽管Just JavaScript对应该或不应该使用哪些特性没有强烈的意见,但我们不会详细讨论松散相等性。它在现代代码库中并不常见,它的规则在语言或我们的思维模式中也没有发挥更大的作用
松散相等规则被广泛认为是JavaScript早期的一个糟糕设计决策,但如果您仍然好奇,可以在这里查看它是如何工作的。不要觉得有压力要记住它——你需要记住其他话题!
值得了解的一个相对常见的用例是
if (x == null) {
// ...
}
这段代码相当于这样写:
if (x === null || x === undefined) {
// ...
}
然而,即使是==的使用也可能在一些团队中引起争议。在使用==之前,最好讨论一下在团队代码库中可以容忍多少==。
回顾
JavaScript有几种等号。它们包括相同价值平等、严格平等和松散平等。
- 理解这种平等有助于防止错误!
- 你经常需要知道什么时候你在处理相同的值,什么时候你在处理两个不同的值。
- 当我们画一个值和变量的图时,相同的值不能出现两次。
Object.is(a,b)
当变量a和b指向图上相同的值时(a, b)为真。 - 相同的值,编写起来有点麻烦,但它也是最容易解释的,这就是我们开始使用它的原因
在实践中,您将使用严格相等,或a === b,最常见的。除了两种罕见的特殊情况外,它等价于相同的值相等:
NaN === NaN
是false
, 即使它们是相同的值.0 === -0
和-0 === 0
是true
, 但它们是不同的值.你可以查看
x
是NaN
通过Number.isNaN(x)
.Loose equality (
==
) 使用一组神秘的规则,通常会被避免.