我在互联网上发现的另一个 JavaScript 问题,但我无法弄清楚它是如何工作的。这个问题主要是问密码是什么。密码不依赖于外部资源,并且不会随时间变化(不依赖于当前日期或时间)。另外,问题表明只有一个正确的密码。我是 JavaScript 初学者,所以如果这是一个简单的标准面试问题,我深表歉意。这是函数:
const checkPassword = a => {
if(a !== (a += '')) return false;
if(a !== (a = a.replace(/[^a-z]/g, ''))) return false;
a = (a.match(/^.{6}|.+/g) || []).join(({} + {})[7]);
a = [...a].reverse().join([] + []);
try{
Function('\'' + a + '\';++1..a')();
return false;
}catch(a){
return true;
}
};
alert(checkPassword(prompt('Enter password:')) ? 'Correct password.' : 'Wrong. Try again.');
起初,这对我来说并不难,因为一切都是开放的,所以我可以简单地逐行跟踪代码并弄清楚它是如何工作的。好的,我知道在检查函数的第一行中,他们检查密码是否是一个字符串(为什么?可以是其他东西吗?)。然后,如果我很好地理解了正则表达式,他们会检查脚本是否仅由小字母组成(或者我错了?)。所以,现在我知道我知道它一定只由字母组成。之后他们执行一些我无法完全理解的奇怪的正则表达式。在我看来,这个正则表达式将匹配整个字符串,那么为什么他们要加入它呢?
然后它们反转字符串并通过一个空数组连接(与通常反转字符串相同还是什么?)。之后在 try block 中我无法理解发生了什么? Function
构造函数在这里实际上做了什么? ++1..a
是什么意思?我只是想知道如何解决这样的问题?
最佳答案
我会直接跳到关键行:
Function('\'' + a + '\';++1..a')();
它创建并立即执行一个新函数,其函数体是从那个看起来很奇怪的字符串中设置的。如果变量 a
比如说,'abcde'
那么新函数的主体将是:
'\'' + 'abcde' + '\';++1..a'
这就像拥有这个功能:
function() {
'abcde';++1..a
}
或者加一些空格:
function() {
'abcde';
++1..a
}
请注意,第一行的字符串是根据 a
中的内容动态设置的。变量,但是 ++1..a
部分是硬编码的。
现在,请注意该函数位于 try/catch()
内 block ,如果新函数运行没有错误则 checkPassword()
将返回false
,但是如果新函数崩溃了checkPassword()
返回true
。换句话说,预计该动态函数的行为将更改为崩溃或不崩溃,具体取决于 a
中的字符串中的内容。变量。
那么函数第一行的什么字符串本身可能会改变函数的行为?只有一种可能性,那就是(将鼠标悬停以显示剧透):
block 引用>
'use strict'
...必须输入密码'tcirtsesu'
因为函数的前几行执行.match()
和.reverse()
.考虑到这一点,
++1..a
是什么并不重要。部分确实如此,但它基本上采用.a
1
的属性(property),即undefined
,并尝试增加它,这......在严格模式下会出错,但在非严格模式下不会出错。
block 引用>为了完整起见,对这些行进行非常简短的解释:
a = (a.match(/^.{6}|.+/g) || []).join(({} + {})[7]); a = [...a].reverse().join([] + []);
.match()
函数返回一个数组。/^.{6}|.+/g
匹配前六个字符,或任意数量的字符,这意味着"abcdefghijkl".match(/^.{6}|.+/g)
返回["abcdef", "ghijkl"]
。然后({} + {})[7]
基本上只是一个空格字符,因为{} + {}
是字符串"[object Object][object Object]"
。因此该行基本上在第六个字符后插入一个空格。
.reverse()
然后行反转结果。
关于JavaScript:猜测密码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41031296/