想要改进这篇文章?提供这个问题的详细答案,包括引文和解释为什么你的答案是正确的。没有足够细节的答案可能会被编辑或删除。
版主注意:请抵制编辑代码或删除此通知的冲动。空白的模式可能是问题的一部分,因此不应被不必要地篡改。如果您在“空白是微不足道的”阵营中,您应该能够按原样接受代码。
(a== 1 && a 2 && a3) 是否有可能在 JavaScript 中计算为 true?
这是一家大型科技公司提出的面试问题。它发生在两周前,但我仍在努力寻找答案。我知道我们在日常工作中从未编写过这样的代码,但我很好奇。
一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会
如果您利用 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 返回一个字符串,那么引擎会尝试将该字符串转换为一个数字,从而为我们提供相同的最终结果,尽管路径稍长。
您可以通过更改隐含的 valueOf() 操作来实现此目的吗?
是的,出于同样的原因, valueOf 可以代替 toString
评论不用于扩展讨论;此对话已moved to chat。
根据 this,将首先尝试数字转换,因此 valueOf 稍好一些。
@Pureferret 等式比较的左侧是一个对象,而不是一个数字。该对象在 i 上具有数字属性不会打扰引擎。 ;)
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。
我无法抗拒 - 其他答案无疑是正确的,但你真的不能跳过以下代码:
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(a1&&a2&&a==3) { console.log(“Why hello there!”) }
从原始问题中的奇数间距来看,我认为这正是面试问题所要寻找的答案——利用看起来像空格的非空格字符。好地方!
@Baracus 是 RonJohn 在他对凯文的回答的评论中注意到奇怪的间距,这让我想起了这种(可怕的)技术,所以我不能因为发现它而受到赞扬。不过,我有点惊讶没有人回答这个问题,因为几年前因为某处的一篇博客文章,它在我的工作中流传——我有点认为现在这是相当普遍的知识。
当然,这作为 standard loophole 被禁止,这也适用于采访。 [需要引用]
考虑到原来的间距,可能会更糟,即使用了变量var ᅠ2 = 3;所以有三个变量aᅠᅠ= 1, ᅠ2 = 3, a = 3(a␣ = 1, ␣2 = 3, a = 3,所以(a␣==1 && a==␣2 && a==3))......
@AL-zami 在两个变量中有一个额外的字符,它在屏幕上显示为一个空格,但被解释为标识符的一部分,这意味着有三个单独的变量 - a、a 和 a - 额外的字符是韩文半角空间。
HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com
有可能的!
变量 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(“是的,这是打印出来的。”); }
是的,我正在尝试同样的事情 :) 所以面试中的正确答案是,“这不会发生在 my 代码中,因为我从不使用 with。”
@Pointy - 而且,我在不允许 with 的严格模式下编程。
@Pointy 在接受的答案中,他们在没有 with 的情况下做了类似的事情,所以它可能会发生
@jorrit 没有人会使用 ==。并且 === 阻止接受的答案
@乔纳斯W。很多人仍然使用 ==,但我没有见过 with,因为......实际上从来没有在 JS 文档之外,上面写着“请不要使用它”。无论如何,一个不错的解决方案。
huntsbot.com提供全网独家一站式外包任务、远程工作、创意产品分享与订阅服务!
没有 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);
huntsbot.com – 高效赚钱,自由工作
without valueOf,嗯...它更间接但基本相同。
我真的很喜欢这个解决方案,因为除了对象自己的连接函数之外,您不会覆盖任何东西,而且它只是一个非常干净且易于阅读的 hack,它使逻辑评估为真。
老实说,我认为这是最好的答案。它没有什么特别之处,只是设置了一些值。即使有基本的 JS 知识也很容易理解。做得好。
这非常有意义,几乎感觉很有用。
我知道大多数答案都是关于滥用 toString 或 valueOf 的,但这个答案让我完全措手不及。非常聪明,我不知道它确实会在内部调用.join,但它完全有道理。
huntsbot.com汇聚了国内外优秀的初创产品创意,可按收入、分类等筛选,希望这些产品与实践经验能给您带来灵感。
如果询问是否可能(不是必须),它可以要求“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) + " 试验,终于成真!!!");休息; } } }
即使我知道其他解决方案,我也会故意给出这个答案,因为它回答了问题,但显然不是他们所追求的。玩愚蠢的游戏,赢得愚蠢的奖品。
但是如果它需要超过 1000 次试验呢?
@Piyin 如果它需要超过 1000 次试验,你就赢了!
我喜欢这个答案,因为将其发挥到极致表明,如果 cpu 的寄存器/缓存在程序运行时被足够的宇宙射线击中,或者如果有人故意执行电源故障以致故障分支的故障分支,这在任何语言中都是可能的if 条件实际上并没有跳转。
最低:1,最高:412。
一个优秀的自由职业者,应该有对需求敏感和精准需求捕获的能力,而huntsbot.com提供了这个机会
当你没有正则表达式什么都做不了时:
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 等等。
@Abdillah 正则表达式对象会记住它匹配的最后一个索引,再次调用 exec 将从该索引开始搜索。 MDN 不是很清楚。
我明白了,所以 this.r 正则表达式对象记住了状态/索引。谢谢!
我建议将字符串传递给 exec,而不是要字符串化的整数。
使用正则表达式,现在你有 two problems
打造属于自己的副业,开启自由职业之旅,从huntsbot.com开始!
如果变量 a 被 2 个网络工作者通过 SharedArrayBuffer 以及一些主脚本访问,这是可能的。可能性很低,但有可能当代码编译成机器码时,web worker 及时更新变量 a 以满足条件 a1、a2 和 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。添加越来越多的列表会降低命中的机会。
老实说,这是最好的答案。所有其他答案都需要刻意尝试做一些非常不直观的事情。这个答案实际上反映了现实世界中可能发生的事情——竞争条件。
不仅如此-我实际上已经在现实世界中看到了这种情况。不是问题中的确切条件,但肯定是在函数开始时检查 (a==1) 并在函数后面检查 (a==2),并且代码满足这两个条件。仅供参考,我第一次看到这种情况发生在汽车发动机控制器中,我们制定了编码标准。第二次是在军用飞机的箔条和照明弹分配器系统中,我在公司的第一天就发现了这个并修复了它,而团队的其他成员仍在讨论这个问题。 (荣誉等级:高!:)
那么,您是否曾与网络工作者一起使用 JavaScript 编写“汽车引擎控制器”和“箔条和火炬分配器系统”?我想我不会再出门了。
@psaxton :) 当然不是——但我们有共享数据的多线程软件。这是所有多线程软件的反模式,并非特定于 Javascript 或 web 工作者。无论您是使用汇编语言、Brainf*ck、Visual BASIC、C 还是 Javascript 进行编程 - 如果您在多线程应用程序中使用共享数据执行此操作,它总是会失败。
我认为这现在是@jontro 答案的精心包装。
保持自己快人一步,享受全网独家提供的一站式外包任务、远程工作、创意产品订阅服务–huntsbot.com
可以在全局范围内使用以下内容来完成。对于 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 是一个局部变量(看起来像),那么这将不起作用。
@jfriend00 你的意思是如果你放置了 var a;某处?
是的。引用 a == 1 意味着 a 是某处的变量,而不是 this 的属性。虽然有一个像全局变量这样的奇怪地方,两者都可能为真,但通常,使用 var a 或 let a 声明变量意味着没有 this 可以让您访问 a 作为代码假定的属性。因此,您的代码显然假设了一些奇怪的全局变量。例如,您的代码不能在 node.js 中运行,也不能在函数内部的严格模式下运行。您应该指定它工作的确切情况,并可能解释它为什么工作。否则,这是误导。
@jfriend00 很确定。不确定它是否会与其他已经回答的问题结合起来增加更多价值。会更新答案
问题是,这个“永远”是真的吗?答案是肯定的,这可能是其中一种情况:a 不是局部变量,而是在全局范围内使用递增的 getter 定义的。
HuntsBot周刊–不定时分享成功产品案例,学习他们如何成功建立自己的副业–huntsbot.com
这也可以使用一系列自覆盖吸气剂:
(这类似于 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(“是的,有可能。”); } })();
请注意,使用 getter 的方法也适用于 ===,而不仅仅是 ==。
此解决方案依赖于 this 作为箭头函数主体内的全局对象。
@Midnightas 我不会将任何其他答案归类为 "pyramid code"。
请注意,这也适用于任意顺序,不是吗?比如,(a == 3 && a == 2 && a == 1)?
huntsbot.com聚合了超过10+全球外包任务平台的外包需求,寻找外包任务与机会变的简单与高效。
或者,您可以为它使用一个类并为检查使用一个实例。
函数 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..
huntsbot.com精选全球7大洲远程工作机会,涵盖各领域,帮助想要远程工作的数字游民们能更精准、更高效的找到对方。
我没有看到这个答案已经发布,所以我也会把这个答案加入其中。这类似于具有半角韩文空间的 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 来查找用于此答案的同形文字。
"Slight discrepancy" 不是我所说的那样。
@hvd 完全取决于您的字体渲染。 This is what I see。
@Jake是的,全宽拉丁小写A不是最大的同形文字(但大写字母变体很棒)。通常,尽管您只需要两个即可获得所需的效果。
您还可以使用 unicode 变体选择器 (U+FE00..U+FE0F)。这些都不是 a:a︀ a︁ a︂。不再担心差异。
原文链接:https://www.huntsbot.com/qa/9r4Z/can-a-1-a-2-a-3-ever-evaluate-to-true?lang=zh_CN&from=csdn
huntsbot.com – 程序员副业首选,一站式外包任务、远程工作、创意产品分享订阅平台。