更深入一点,变量赋值和严格相等如何在 Javascript 中工作
Posted
技术标签:
【中文标题】更深入一点,变量赋值和严格相等如何在 Javascript 中工作【英文标题】:How variable assignment and strict equality work in Javascript, in a little more depth 【发布时间】:2018-07-02 13:09:42 【问题描述】:我们都知道JS有objects和一组primitives。
让我们检查以下作业。
a = 'foo';
b = a;
c = 'foo'
a === b; //true
a = b = c = undefined;
我多年来在 JS 中可视化变量赋值过程的方式是这样的。
a = 'foo';
一个新的原始字符串foo
被创建并添加到一个内存位置。变量a
现在指向内存中的那个位置。
b = a
变量b
指向与a
相同的内存位置,这意味着它指向foo
。
c = 'foo'
原始字符串foo
已经存在于内存中,所以变量c
只是指向那个
a === b; //true
变量a
和b
通过引用进行比较,这意味着唯一要检查的是它们是否指向内存中的相同位置,而不是它们的值是否相同。这意味着无论字符串有多长,这都应该是一个快速的操作。
a = b = c = undefined
变量a
、b
、c
都指向原语undefined
。原语foo
没有被任何变量指向,所以它被垃圾回收了。
以上所有内容也应适用于对象属性。
我 101% 确信这就是 JS 的工作原理,直到今天我与一位同事交谈时,他和我一样确信当比较两个变量时,即使是严格相等 (===
) ,它们是按值比较而不是按引用比较。
因此,如果我们必须比较两个都分配了非常大的字符串的变量,例如
a = 'a huge string';
b = 'a huge string';
a === b; //true, takes 1ms
与两个变量只分配一个字母字符串相比,这种相等性检查将花费更长的时间。例如
a = 'a small string';
b = 'a small string';
a === b; //true, takes 0.1ms
总结
我的任何要点(我的理解)是否不正确?严格相等是否比较值而不是引用?
欢迎并鼓励技术性回答。
谢谢。
【问题讨论】:
您的假设有一个重要的警告。您在某种程度上将单个 JS 引擎实现细节与官方 ECMAScript 规范混为一谈(规范中并未概述所有这些行为) 如果我正确理解了您的问题,重点是字符串和数字是按值进行比较(并为此分配),而对象(数组、函数)是按引用进行比较(并分配)。考虑var a = ; var b =
但a !== b
。正如您所展示的,对于字符串,它们是相等的。
【参考方案1】:
基于 ECMAScript 规范,===
比较值,而不是引用,除非这些值是对象。
对于字符串比较,它们按字典顺序进行比较,就像检查所有字符是否按相同顺序相等。
如果 x 和 y 是完全相同的代码单元序列(相同的长度和对应索引处的相同代码单元),则返回 true;否则返回false。
这是a === b
的一般算法:
// if both are undefined, return true
// if both are null, return true
// if both are numbers
// if a is NaN, return false
// if b is NaN, return false
// if are equal numeric values, return true
// if a is +0 and b is -0, return true
// if b is +0 and a is -0, return true
// return false
// if both are strings
// if all chars equal and in the same order, return true
// return false
// if both are booleans
// if both are true or both are false, return true
// return false
// if both are objects
// if are equal references, return true
// return false
// return false
我不久前写了一个 small tool,演示了可能有帮助的 ==
和 ===
算法(根据 ES5 规范)。
现在,就从已定义的字符串中重用内存而言,例如您的示例 a = 'foo'
和 c = 'foo'
出于效率原因指向相同的内存,这是引擎可以进行的优化以使事情变得更快,但不是规范的一部分。
其实这叫String Interning,很多语言都这样做。
【讨论】:
这肯定是一个令人大开眼界的答案,谢谢。所以,从技术上讲,我的同事是对的 :) 好吧,再一次,这是理论和实践之间的一条细线:)。实际上,大多数引擎都会进行字符串实习,所以我想说你们都需要先定义判断规则,然后再决定谁是对的哈哈【参考方案2】:当您使用原始类型(数字、字符串、布尔值)时,您是在比较它们的值。
"string one" == "string one"; // true
3 == 3; // true
false == false; // true
即使是未定义的作品也类似:
undefined == undefined; // true
NaN 除外:
NaN == NaN; // false
当您比较对象时,您会比较它们的引用。例如:
var obj1 = "name": "Charles" ;
var obj2 = "name": "Charles" ;
obj1 == obj2; // false
obj1 === obj2; // false
【讨论】:
以上是关于更深入一点,变量赋值和严格相等如何在 Javascript 中工作的主要内容,如果未能解决你的问题,请参考以下文章
PHP 等效于 Perl 的“使用严格”(要求在使用前初始化变量)