想要改进这篇文章?提供这个问题的详细答案,包括引文和解释为什么你的答案是正确的。没有足够细节的答案可能会被编辑或删除。
版主注意:请抵制编辑代码或删除此通知的冲动。空白的模式可能是问题的一部分,因此不应被不必要地篡改。如果您在“空白是微不足道的”阵营中,您应该能够按原样接受代码。
(a== 1 && a ==2 && a==3)
是否有可能在 JavaScript 中计算为 true
?
这是一家大型科技公司提出的面试问题。它发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
===
时不要使用 ==
,有一个禁止非 ASCII 变量名的编码标准,并且有一个强制执行前两个道德的 linting 过程。
如果您利用 how ==
works,您可以简单地创建一个具有自定义 toString
(或 valueOf
)函数的对象,该函数在每次使用时更改它返回的内容,从而满足所有三个条件。
const a = { i: 1, toString: function () { return a.i++; } } if(a == 1 && a == 2 && a == 3) { console.log('Hello World!'); }
这个工作的原因是由于使用了松散的相等运算符。使用松散相等时,如果其中一个操作数的类型与另一个不同,引擎将尝试将一个操作数转换为另一个。对于左侧的对象和右侧的数字,它将尝试通过首先调用 valueOf
(如果它是可调用的)将对象转换为数字,如果失败,它将调用 toString
。在这种情况下,我使用 toString
只是因为想到它,valueOf
会更有意义。如果我改为从 toString
返回一个字符串,那么引擎会尝试将该字符串转换为一个数字,从而为我们提供相同的最终结果,尽管路径稍长。
我无法抗拒 - 其他答案无疑是正确的,但你真的不能跳过以下代码:
var aᅠ = 1;变量 a = 2;变量ᅠa = 3; if(aᅠ==1 && a== 2 &&ᅠa==3) { console.log("你好!") }
请注意 if
语句中的奇怪间距(我从您的问题中复制)。它是半角 Hangul(对于那些不熟悉的人来说是韩语),它是一个 Unicode 空格字符,ECMA 脚本不会将其解释为空格字符 - 这意味着它是标识符的有效字符。因此,有三个完全不同的变量,一个是韩文在 a 之后,一个是在它之前,最后一个是只有 a。用 _
替换空格以提高可读性,相同的代码如下所示:
变量 a_ = 1;变量 a = 2;变量_a = 3; if(a_==1 && a== 2 &&_a==3) { console.log("为什么你好!") }
查看the validation on Mathias' variable name validator。如果这个奇怪的间距实际上包含在他们的问题中,我确信这是对这种答案的暗示。
不要这样做。严重地。
编辑:我注意到(尽管不允许启动变量)变量名称中也允许使用 Zero-width joiner 和 Zero-width non-joiner 字符 - 请参阅 Obfuscating JavaScript with zero-width characters - pros and cons?。
这将如下所示:
变量 a = 1;变量 a= 2; //一个零宽度字符 var a= 3; //两个零宽度字符(或者你可以使用另一个) if(a==1&&a==2&&a==3) { console.log("Why hello there!") }
var ᅠ2 = 3
;所以有三个变量aᅠᅠ= 1, ᅠ2 = 3, a = 3
(a␣ = 1, ␣2 = 3, a = 3
,所以(a␣==1 && a==␣2 && a==3)
)......
有可能的!
变量 i = 0; with({ get a() { return ++i; } }) { if (a == 1 && a == 2 && a == 3) console.log("wohoo"); }
这在 with
语句中使用 getter 来让 a
评估为三个不同的值。
...这仍然不意味着这应该在实际代码中使用...
更糟糕的是,这个技巧也适用于使用 ===
。
变量 i = 0; with({ get a() { return ++i; } }) { if (a !== a) console.log("是的,这是打印出来的。"); }
with
。”
with
的严格模式下编程。
with
的情况下做了类似的事情,所以它可能会发生
==
。并且 ===
阻止接受的答案
==
,但我没有见过 with
,因为......实际上从来没有在 JS 文档之外,上面写着“请不要使用它”。无论如何,一个不错的解决方案。
没有 getter 或 valueOf 的示例:
a = [1,2,3]; a.join = a.shift; console.log(a == 1 && a == 2 && a == 3);
这是因为 ==
调用了 toString
,而 toString
又为数组调用了 .join
。
另一种解决方案,使用 Symbol.toPrimitive
,它是 toString/valueOf
的 ES6 等价物:
让我 = 0;让 a = { [Symbol.toPrimitive]: () => ++i }; console.log(a == 1 && a == 2 && a == 3);
without valueOf
,嗯...它更间接但基本相同。
toString
或 valueOf
的,但这个答案让我完全措手不及。非常聪明,我不知道它确实会在内部调用.join
,但它完全有道理。
如果询问是否可能(不是必须),它可以要求“a”返回一个随机数。如果它依次生成 1、2 和 3,那将是正确的。
with({ get a() { return Math.floor(Math.random()*4); } }){ for(var i=0;i<1000;i++){ if (a == 1 && a == 2 && a == 3){ console.log("经过" + (i+1) + " 试验,终于成真!!!");休息; } } }
当你没有正则表达式什么都做不了时:
var a = { r: /\d/g, valueOf: function(){ return this.r.exec(123)[0] } } if (a == 1 && a == 2 && a == 3) {控制台.log("!") }
它之所以起作用,是因为当 Object 与基元(例如 Number)进行比较时调用的自定义 valueOf
方法。主要技巧是 a.valueOf
每次都返回新值,因为它在带有 g
标志的正则表达式上调用 exec
,这会导致每次找到匹配项时更新该正则表达式的 lastIndex
。所以第一次 this.r.lastIndex == 0
匹配 1
并更新 lastIndex
: this.r.lastIndex == 1
,所以下一次正则表达式将匹配 2
等等。
exec
将从该索引开始搜索。 MDN 不是很清楚。
this.r
正则表达式对象记住了状态/索引。谢谢!
exec
,而不是要字符串化的整数。
如果变量 a
被 2 个网络工作者通过 SharedArrayBuffer 以及一些主脚本访问,这是可能的。可能性很低,但有可能当代码编译成机器码时,web worker 及时更新变量 a
以满足条件 a==1
、a==2
和 a==3
。
这可以是 web worker 和 JavaScript 中的 SharedArrayBuffer 提供的多线程环境中的竞争条件示例。
这是上面的基本实现:
main.js
// Main Thread
const worker = new Worker('worker.js')
const modifiers = [new Worker('modifier.js'), new Worker('modifier.js')] // Let's use 2 workers
const sab = new SharedArrayBuffer(1)
modifiers.forEach(m => m.postMessage(sab))
worker.postMessage(sab)
worker.js
let array
Object.defineProperty(self, 'a', {
get() {
return array[0]
}
});
addEventListener('message', ({data}) => {
array = new Uint8Array(data)
let count = 0
do {
var res = a == 1 && a == 2 && a == 3
++count
} while(res == false) // just for clarity. !res is fine
console.log(`It happened after ${count} iterations`)
console.log('You should\'ve never seen this')
})
修饰符.js
addEventListener('message' , ({data}) => {
setInterval( () => {
new Uint8Array(data)[0] = Math.floor(Math.random()*3) + 1
})
})
在我的 MacBook Air 上,它在第一次尝试大约 100 亿次迭代后发生:
https://i.stack.imgur.com/wjNp9.png
第二次尝试:
https://i.stack.imgur.com/wFrAt.png
正如我所说,机会很小,但只要有足够的时间,它就会达到条件。
提示:如果在您的系统上花费的时间太长。仅尝试 a == 1 && a == 2
并将 Math.random()*3
更改为 Math.random()*2
。添加越来越多的列表会降低命中的机会。
可以在全局范围内使用以下内容来完成。对于 nodejs
,请在下面的代码中使用 global
而不是 window
。
变量值 = 0; Object.defineProperty(window, 'a', { get: function() { return ++val; } }); if (a == 1 && a == 2 && a == 3) { console.log('yay'); }
这个答案通过定义一个 getter 来检索变量来滥用执行上下文中全局范围提供的隐式变量。
a
是 this
的属性,但它似乎不是。如果 a
是一个局部变量(看起来像),那么这将不起作用。
a == 1
意味着 a
是某处的变量,而不是 this
的属性。虽然有一个像全局变量这样的奇怪地方,两者都可能为真,但通常,使用 var a
或 let a
声明变量意味着没有 this
可以让您访问 a
作为代码假定的属性。因此,您的代码显然假设了一些奇怪的全局变量。例如,您的代码不能在 node.js 中运行,也不能在函数内部的严格模式下运行。您应该指定它工作的确切情况,并可能解释它为什么工作。否则,这是误导。
a
不是局部变量,而是在全局范围内使用递增的 getter 定义的。
这也可以使用一系列自覆盖吸气剂:
(这类似于 jontro 的解决方案,但不需要计数器变量。)
(() => { "use strict"; Object.defineProperty(this, "a", { "get": () => { Object.defineProperty(this, "a", { "get": () => { Object.defineProperty(this, "a", { "get": () => { return 3; } }); return 2; }, 可配置: true }); return 1; }, 可配置: true }); if (a == 1 && a == 2 && a == 3) { document.body.append("是的,有可能。"); } })();
===
,而不仅仅是 ==
。
this
作为箭头函数主体内的全局对象。
(a == 3 && a == 2 && a == 1)
?
或者,您可以为它使用一个类并为检查使用一个实例。
函数 A() { 变量值 = 0; this.valueOf = function () { return ++value; }; } var a = 新的 A; if (a == 1 && a == 2 && a == 3) { console.log('bingo!'); }
编辑
使用 ES6 类,它看起来像这样
类 A { 构造函数() { this.value = 0; this.valueOf(); } valueOf() { 返回 this.value++; }; } 让 a = 新的 A; if (a == 1 && a == 2 && a == 3) { console.log('bingo!'); }
function A() {value = 0;
?
valueOf
被覆盖,this method is usually called automatically by JavaScript behind the scenes, and not explicitly in code
所以当我们比较它的值时,它实际上增加了 a..
我没有看到这个答案已经发布,所以我也会把这个答案加入其中。这类似于具有半角韩文空间的 Jeff's answer。
变量 a = 1; var a = 2;变量а = 3; if(a == 1 && a == 2 && а == 3) { console.log("为什么你好!") }
您可能会注意到与第二个略有差异,但第一个和第三个与肉眼相同。所有 3 个都是不同的字符:
a
- 拉丁文小写 A
a
- 全角拉丁文小写 A
а
- 西里尔小写 A
通用术语是“同形文字”:看起来相同的不同 unicode 字符。通常很难得到完全无法区分的三个,但在某些情况下你会很幸运。 A、Α、А 和 Ꭺ 会更好(分别为拉丁语 A、Greek Alpha、Cyrillic-A 和 Cherokee-A;不幸的是,希腊语和切诺基语的小写字母与拉丁语 a
差别太大:{ 5}、ꭺ
等对上述代码段没有帮助)。
那里有一整类同形文字攻击,最常见的是假域名(例如。wikipediа.org
(西里尔文)与 wikipedia.org
(拉丁文)),但它也可以出现在代码中;通常被称为卑鄙(如评论中所述,[underhanded] 问题现在在 PPCG 上是题外话,但曾经是这类事情会出现的一种挑战)。我使用 this website 来查找用于此答案的同形文字。
a
:a︀
a︁
a︂
。不再担心差异。
对的,这是可能的! 😎
» JavaScript
如果=()=>!0;变量 a = 9; if(a==1 && a== 2 && a==3) { document.write("
上面的代码是一个简短的版本(感谢@Forivin 在评论中的注释),下面的代码是原始的:
变量 a = 9; if(a==1 && a== 2 && a==3) { //console.log("是的,有可能!😎") document.write("
如果您只是看到我的代码的顶部并运行它,您会说哇,怎么样?所以我认为说是的就足够了,对有人对你说:没有什么是不可能的技巧:我在 if 后面使用了一个隐藏字符来制作一个名称类似于 if 的函数。在 JavaScript 中我们不能覆盖关键字,所以我被迫使用这种方式。如果是假的,但在这种情况下它对你有用!
“ C#
我还写了一个 C# 版本(增加属性值技术):
static int _a;
public static int a => ++_a;
public static void Main()
{
if(a==1 && a==2 && a==3)
{
Console.WriteLine("Yes, it is possible!😎");
}
}
if=()=>!0
document.write
?无论其他答案如何,这都是不被录用的万无一失的方法。
console.log
写了我的答案,但我将其更改为 document.write。我真的总是在我的代码中使用 console.log
,但在这里我只想在 StackOverflow 代码片段框中向用户显示一个文本。所以我想展示我的信息比 console.log
生成的信息更漂亮。单击我的答案和其他答案上的 Run Code Snippet
按钮。 SO Code Snippet 让我可以使用 html、JS 和 CSS,然后我想在我的答案中使用它并让它变得更好。我认为它没有任何负面影响,也没有使我的答案变大或完成。
JavaScript
一个==一个+1
在 JavaScript 中,没有 integers 而只有 Number
,它们被实现为双精度浮点数。
这意味着如果一个 Number a
足够大,则可以认为它等于三个连续的整数:
a = 100000000000000000 if (a == a+1 && a == a+2 && a == a+3){ console.log("精度损失!"); }
诚然,这并不是面试官所要求的(它不适用于 a=0
),但它不涉及任何隐藏函数或运算符重载的技巧。
其他语言
作为参考,Ruby 和 Python 中有 a==1 && a==2 && a==3
个解决方案。稍作修改,在 Java 中也可以实现。
红宝石
使用自定义 ==
:
class A
def ==(o)
true
end
end
a = A.new
if a == 1 && a == 2 && a == 3
puts "Don't do this!"
end
或增加的 a
:
def a
@a ||= 0
@a += 1
end
if a == 1 && a == 2 && a == 3
puts "Don't do this!"
end
Python
您可以为新类定义 ==
:
class A:
def __eq__(self, who_cares):
return True
a = A()
if a == 1 and a == 2 and a == 3:
print("Don't do that!")
或者,如果您喜欢冒险,redefine the values of integers:
import ctypes
def deref(addr, typ):
return ctypes.cast(addr, ctypes.POINTER(typ))
deref(id(2), ctypes.c_int)[6] = 1
deref(id(3), ctypes.c_int)[6] = 1
deref(id(4), ctypes.c_int)[6] = 1
print(1 == 2 == 3 == 4)
# True
它可能会出现段错误,具体取决于您的系统/解释器。
python 控制台因上述代码而崩溃,因为可能在后台使用了 2
或 3
。如果您使用不太常见的整数,它可以正常工作:
>>> import ctypes
>>>
>>> def deref(addr, typ):
... return ctypes.cast(addr, ctypes.POINTER(typ))
...
>>> deref(id(12), ctypes.c_int)[6] = 11
>>> deref(id(13), ctypes.c_int)[6] = 11
>>> deref(id(14), ctypes.c_int)[6] = 11
>>>
>>> print(11 == 12 == 13 == 14)
True
爪哇
可以修改 Java Integer
cache:
package stackoverflow;
import java.lang.reflect.Field;
public class IntegerMess
{
public static void main(String[] args) throws Exception {
Field valueField = Integer.class.getDeclaredField("value");
valueField.setAccessible(true);
valueField.setInt(1, valueField.getInt(42));
valueField.setInt(2, valueField.getInt(42));
valueField.setInt(3, valueField.getInt(42));
valueField.setAccessible(false);
Integer a = 42;
if (a.equals(1) && a.equals(2) && a.equals(3)) {
System.out.println("Bad idea.");
}
}
}
Integer a = 42
一起工作(或者不能)?据我了解自动装箱,Integer a = 42; a == 1 && a == 2 && a == 3
应该装箱所有的整数。或者这是否为比较而拆箱?
Integer == int
似乎导致拆箱。但是使用 Integer#equals(int)
会强制自动装箱,所以它可以工作。感谢您的评论!
Numbers
,基本类似于double
。它们看起来像整数,您可以像整数一样使用它们,但它们仍然不是整数。我不认为 n == n + 1
对于 Java/Python/C/Ruby/ 中的整数是真的...
这是 @Jeff's answer* 的反转版本,其中隐藏字符(U+115F、U+1160 或 U+3164)用于创建看起来像 1
、2
和 3
的变量。
变量 a = 1; var ᅠ1 = a; var ᅠ2 = a; var ᅠ3 = a; console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );
这个答案可以通过使用零宽度非连接器 (U+200C) 和零宽度连接器 (U+200D) 来简化。这两个字符都可以在标识符中使用,但不能在开头:
变量 a = 1;变量 a = 2;变量 a = 3; console.log(a == 1 && a == 2 && a == 3); /**** 变量 a = 1; var a\u200c = 2; var a\u200d = 3; console.log(a == 1 && a\u200c == 2 && a\u200d == 3); ****/
其他技巧也可以使用相同的想法,例如通过使用 Unicode 变体选择器来创建看起来完全相似的变量 (a︀ = 1; a︁ = 2; a︀ == 1 && a︁ == 2; // true
)。
面试的第一条规则;永远不要说不可能。
无需隐藏角色诡计。
window.__defineGetter__( 'a', function(){ if( typeof i !== 'number' ){ // 在全局命名空间中定义 i,这样函数运行后不会丢失 i = 0; } return ++i ; }); if( a == 1 && a == 2 && a == 3 ){ console.log( '天哪,我们做了什么?' ); }
__defineGetter__
实际上不是 js 语言的一部分,只是 defineProperty
的丑陋版本。 typeof
不是一个函数,这个未声明的 i
实在是太糟糕了。似乎仍然值得 40 票:/
__defineGetter__
,但它显然在我的 FireFox v 57.0.4 中执行,所以我选择展示它而不是 defineProperty()
,因为遗留代码是真实的,不能被忽略。不管丑陋如何,以我所做的方式声明 i
是众所周知的/记录在案的行为。也许我只是在 PCG 心情¯\_(ツ)_/¯
老实说,无论是否有办法评估它是否正确(正如其他人所表明的那样,有多种方法),作为一个进行过数百次采访的人来说,我正在寻找的答案将是类似于:
“好吧,也许在一些对我来说不是很明显的奇怪情况下是可以的……但如果我在真实代码中遇到这种情况,那么我会使用常见的调试技术来弄清楚它是如何以及为什么在做它正在做的事情然后立即重构代码以避免这种情况......但更重要的是:我绝对不会首先编写该代码,因为那是复杂代码的定义,我努力从不编写复杂代码”。
我想有些面试官会因为提出一个显然意味着非常棘手的问题而感到生气,但我不介意有意见的开发人员,特别是当他们可以用理性的想法支持它并且可以将我的问题与我的问题相吻合时关于自己的有意义的陈述。
如果你曾经遇到过这样的面试问题(或注意到代码中同样出乎意料的行为),请考虑一下什么样的事情可能会导致乍一看似乎不可能的行为:
编码:在这种情况下,您正在查看的变量不是您认为的变量。如果您故意使用同形文字或空格字符弄乱 Unicode 以使变量的名称看起来像另一个变量的名称,则可能会发生这种情况,但也可能会意外引入编码问题,例如从包含意外 Unicode 代码的 Web 复制和粘贴代码时点(例如,因为内容管理系统进行了一些“自动格式化”,例如将 fl 替换为 Unicode 'LATIN SMALL LIGATURE FL' (U+FB02))。竞争条件:可能会发生竞争条件,即代码未按开发人员预期的顺序执行的情况。竞争条件经常发生在多线程代码中,但多线程并不是竞争条件成为可能的必要条件——异步就足够了(不要混淆,异步并不意味着在后台使用多个线程)。请注意,因此 JavaScript 也不能仅仅因为它是单线程的而不受竞争条件的影响。有关简单的单线程(但异步)示例,请参见此处。然而,在单个语句的上下文中,竞争条件在 JavaScript 中将很难被击中。带有 web worker 的 JavaScript 有点不同,因为你可以有多个线程。 @mehulmpt 向我们展示了一个使用网络工作者的出色概念证明。副作用:相等比较操作的副作用(不必像这里的示例那样明显,副作用通常非常微妙)。
此类问题可能出现在许多编程语言中,不仅是 JavaScript,因此我们在这里没有看到经典的 JavaScript WTFs 之一1。
当然,这里的面试题和样本看起来都很做作。但它们很好地提醒人们:
副作用可能会变得非常讨厌,一个设计良好的程序应该没有不需要的副作用。
多线程和可变状态可能是有问题的。
不正确地进行字符编码和字符串处理会导致严重的错误。
1 例如,您可以在完全不同的编程语言 (C#) 中找到一个显示副作用(很明显)的示例here。
这是另一个变体,使用数组弹出你想要的任何值。
const a = { n: [3,2,1], toString: function () { return anpop(); } } if(a == 1 && a == 2 && a == 3) { console.log('Yes'); }
好的,另一个使用生成器的 hack:
常量值 = 函数* () { 让 i = 0; while(true) 产生 ++i; }(); Object.defineProperty(this, 'a', { get() { return value.next().value; } }); if (a === 1 && a === 2 && a === 3) { console.log('yo!'); }
this
作为窗口对象)
使用 Proxies:
var a = new Proxy({ i: 0 }, {
get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3);
代理基本上假装是一个目标对象(第一个参数),但拦截目标对象上的操作(在本例中是“获取属性”操作),以便有机会做一些默认对象行为以外的事情。在这种情况下,当 ==
强制其类型以将其与每个数字进行比较时,会在 a
上调用“获取属性”操作。有时候是这样的:
我们创建一个目标对象,{ i: 0 },其中 i 属性是我们的计数器 我们为目标对象创建一个 Proxy 并将其分配给 a 对于每个 a == 比较,a 的类型被强制转换为原始值 这种类型强制导致在内部调用 a[Symbol.toPrimitive]() 代理拦截使用“get handler”获取 a[Symbol.toPrimitive] 函数 Proxy 的“get handler”检查获取的属性是 Symbol.toPrimitive,在这种情况下它递增然后从目标对象返回计数器:++target.i。如果正在检索不同的属性,我们只需要返回默认属性值 target[name]
所以:
var a = ...; // a.valueOf == target.i == 0
a == 1 && // a == ++target.i == 1
a == 2 && // a == ++target.i == 2
a == 3 // a == ++target.i == 3
与大多数其他答案一样,这仅适用于松散的相等检查 (==
),因为严格的相等检查 (===
) 不会执行代理可以拦截的类型强制。
Symbol.toPrimitive
也同样有效。
实际上,在每种编程语言中,问题第一部分的答案都是“是”。例如,这是在 C/C++ 的情况下:
#define a (b++)
int b = 1;
if (a ==1 && a== 2 && a==3) {
std::cout << "Yes, it's possible!" << std::endl;
} else {
std::cout << "it's impossible!" << std::endl;
}
相同,但不同,但仍然相同(可以“测试”多次):
const a = { valueOf: () => this.n = (this.n || 0) % 3 + 1} if(a == 1 && a == 2 && a == 3) { console.log('你好世界!'); } if(a == 1 && a == 2 && a == 3) { console.log('Hello World!'); }
我的想法是从 Number 对象类型方程的工作原理开始的。
一个使用符号的 ECMAScript 6 答案:
const a = {value: 1};
a[Symbol.toPrimitive] = function() { return this.value++ };
console.log((a == 1 && a == 2 && a == 3));
由于 ==
的使用,JavaScript 应该将 a
强制转换为接近第二个操作数(在本例中为 1
、2
、3
)的内容。但在 JavaScript 尝试自行解决强制转换之前,它会尝试调用 Symbol.toPrimitive
。如果您提供 Symbol.toPrimitive
JavaScript 将使用您的函数返回的值。如果不是,JavaScript 将调用 valueOf
。
我认为这是实现它的最少代码:
i=0,a={valueOf:()=>++i} if (a == 1 && a == 2 && a == 3) { console.log('Mind === Blown'); }
使用自定义 valueOf
创建一个虚拟对象,该对象会在每次调用时递增一个全局变量 i
。 23个字符!
这个使用 defineProperty 具有很好的副作用,导致全局变量!
var _a = 1 Object.defineProperty(this, "a", { "get": () => { return _a++; }, 可配置:true }); console.log(a) console.log(a) console.log(a)
a
上使用闭包:get: (a => () => ++a)(0),
不需要全局。
通过在类声明中覆盖 valueOf
,可以做到:
class Thing {
constructor() {
this.value = 1;
}
valueOf() {
return this.value++;
}
}
const a = new Thing();
if(a == 1 && a == 2 && a == 3) {
console.log(a);
}
发生的情况是在每个比较运算符中调用 valueOf
。在第一个中,a
将等于 1
,在第二个中,a
将等于 2
,依此类推,因为每次调用 valueOf
,a
的值为递增。
因此,console.log 将触发并输出(无论如何在我的终端中)Thing: { value: 4}
,表明条件为真。
正如我们已经知道的那样,loose equality operator (==) 的秘密将尝试将这两个值转换为一个通用类型。结果,将调用一些函数。
ToPrimitive(A) 尝试通过在 A 上调用不同的 A.toString 和 A.valueOf 方法序列,将其对象参数转换为原始值。
因此,使用整数中的 Symbol.toPrimitive
、.toString
、.valueOf
的其他答案也是如此。我会建议使用像这样的 Array.pop
数组的解决方案。
let a = { array: [3, 2, 1], toString: () => a.array.pop() }; if(a == 1 && a == 2 && a == 3) { console.log('Hello World!'); }
通过这种方式,我们可以处理这样的文本
let a = { array: ["World", "Hello"], toString: () => a.array.pop() }; if(a == "Hello" && a == "World") { console.log('Hello World!'); }
valueOf()
操作来实现此目的吗?valueOf
稍好一些。i
上具有数字属性不会打扰引擎。 ;)