问题描述
我正在用 JavaScript 做 Konami Code 练习,虽然我自己让它工作,但答案对我来说毫无意义。有人愿意解释吗?
我的解决方案:
const pressed = [];
var secretCode = 'wesbos';
window.addEventListener('keyup',e => {
//My code
if (pressed.length < 6) {
pressed.push(e.key)
} else if (pressed.length === 6) {
pressed.shift()
pressed.push(e.key)
console.log(pressed)
}
//End my code
if (pressed.join('').toLowerCase() === secretCode) {
console.log("SECRET COMMAND ACTION CODE TRIGGERED! COMMENCE KAMEHAMEHA");
$.getScript('http://www.cornify.com/js/cornify.js',function() {
cornify_add();
$(document).keydown(cornify_add);
});
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
https://medium.com/@nikkoortega/key-sequence-detection-f90773e3aa60 的回答,我不明白:
const pressed = [];
const secretCode = 'wesbos';
window.addEventListener('keyup',e => {
//Answer code
pressed.push(e.key)
pressed.splice(-secretCode.length - 1,pressed.length - secretCode.length)
//End answer code
if (pressed.join('').toLowerCase() === secretCode) {
console.log("SECRET COMMAND ACTION CODE TRIGGERED! COMMENCE KAMEHAMEHA");
}
})
解决方法
代码的重点是创建一个 queue,一个 FIFO 结构。
Array#splice
是一个令人困惑的就地函数,它删除从第一个参数到第二个参数的元素,并使用负索引包装。第三个参数可选地添加新元素,但此处未使用。
在解决方案中,-secretCode.length - 1
基本上是一个常量,如果密码的长度为 6,则为 -7。这完全没有意义,可以用 0 替换,因为他们真的想访问第一个元素,这是应该出队的。
第二个参数是 pressed.length - secretCode.length
,它计算到目前为止收集的密钥数量与密码总长度之间的差值。这是 <= 0
直到按下的队列超过密码的大小,此时它是 1,这意味着第一个元素出列,因为 splice
调用看起来像 splice(0,1)
。当使用 splice
或 splice(0,-1)
等负数调用 splice(0,0)
时,它没有任何效果。
这是一个简化和带注释的版本:
const pressed = [];
var secretCode = 'wesbos';
window.addEventListener('keyup',e => {
pressed.push(e.key);
console.log(
"after push,before splice",pressed + "",pressed.length - secretCode.length
);
pressed.splice(0,pressed.length - secretCode.length);
console.log("after splice",pressed + "");
console.log("______________");
if (pressed.join('').toLowerCase() === secretCode) {
console.log("SECRET COMMAND ACTION CODE TRIGGERED! COMMENCE KAMEHAMEHA");
}
})
<p>type: "wesbos"</p>
我的观点是通常应该避免使用 splice
,尤其是在处理负索引和添加元素时。它是线性的、聪明的、难以理解的,如果您必须从数组的中间弹出元素,通常会使用错误的数据结构。
我更喜欢你的方法,但我会这样写:
const pressed = [];
var secretCode = 'wesbos';
window.addEventListener('keyup',e => {
pressed.push(e.key);
while (pressed.length > secretCode.length) {
pressed.shift();
}
if (pressed.join('').toLowerCase() === secretCode) {
console.log("SECRET COMMAND ACTION CODE TRIGGERED! COMMENCE KAMEHAMEHA");
}
})
<p>type: "wesbos"</p>
while
可能是 if
,因为我们知道我们总是添加 1 个元素,但保留它 while
也没有什么坏处——关键是它强制出队,直到队列与目标词的大小相同。
JS 的一个恼人的事情是它没有一个好的内置队列结构,所以我们必须shift()
一个数组。这仍然是线性的,但至少它比 splice
更清楚地传达了实现队列的意图,Application.OpenForms
始终在索引 0 处运行并且始终删除不超过 1 个元素,尽管存在负索引混淆。