我在codeschool.com上做了一些javascript挑战。 在功能表达式章节中,我遇到了以下奇怪的错误。
在下面的脚本中 - 可以重构一遍,我知道 - 在第二次运行后,'queue'变量被赋值为'undefined'。
第一次迭代:
第二次迭代:
第三次迭代 - 发生错误(?):
首先我认为在codeschool的结尾有些问题,但在尝试使用chrome的开发工具运行代码后,我得到了相同的结果。 据我所知,没有任何异步应该发生,这可能会弄乱任何东西?
var puzzlers = [
function(a) { return 8 * a - 10; },
function(a) { return (a - 3) * (a - 3) * (a - 3); },
function(a) { return a * a + 4; },
function(a) { return a % 5; }
];
var start = 2;
var applyAndEmpty = function(input, queue) {
for (var i = 0; i < queue.length; i++) {
alert(queue);
if (i === 0) {
alert("hello 1");
var output = queue.shift()(input);
} else if (queue.length === 1) {
alert("hello 2");
return queue.shift()(output);
} else {
alert("hello 3");
output = queue.shift()(output);
alert(queue);
}
}
};
alert(applyAndEmpty(start, puzzlers));
谢谢!
答案 0 :(得分:3)
代码审核
这段代码中发生了一些不好的事情;我们应该先审视它们。为方便起见,我将使用alert
调用替换所有console.log
个调用 - 控制台可以更好地进行调试。
好的第一个问题是您在queue.shift()
循环中使用for
。 Array.prototype.shift
将更改数组的长度,因此您并不打算在循环内使用它(在非常专业的情况之外)。
因此,每次循环播放时,i
上升一个,queue.length
下降一个 - 两个值相互收敛,这意味着您永远不会真正触及{中的所有值{1}}
<强>重构强>
我们可以通过非常简单的函数调整来解决这个问题 - 删除queue
循环! for
对我们有效增加,但一次删除一个元素。我们需要做的就是检查queue.shift()
是否为空 - 如果是,我们已完成,否则 queue.length
一个项目离开队列并重复
shift
&#13;
更多教训
有关手动逐步执行数组的重要事项。您执行一个以下选项
<强> 1。在尝试获取值之前检查数组是否为空
var applyAndEmpty = function(input, queue) {
console.log(input)
if (queue.length === 0)
return input;
else
return applyAndEmpty(queue.shift()(input), queue)
}
var puzzlers = [
function(a) { return 8 * a - 10; },
function(a) { return (a - 3) * (a - 3) * (a - 3); },
function(a) { return a * a + 4; },
function(a) { return a % 5; }
];
var start = 2;
console.log(applyAndEmpty(start, puzzlers));
// [initial input] 2
// 8 * 2 - 10 = 6
// (6 - 3) * (6 - 3) * (6 - 3) = 27
// 27 * 27 + 4 = 733
// 733 % 5 = 3
// [final output] = 3
console.log(puzzlers); // []
<强> 2。 null-检查你想要获得的东西
// there are no items so we cannot get one
if (arr.length === 0)
doSomething;
// we know there is at least one item, so it is safe to get one
else
doOtherThing( arr.shift() )
你个人选择使用一个而不是另一个,所以我通常不喜欢这种无效检查。我相信在尝试抓住它之前检查数组是否有价值会更好。
执行 BOTH 这些选项将是一个逻辑错误。如果我们检查数组的长度是非0,我们可以推断出我们有一个x - 因此我们不必对x进行空检查。
<强>说明强>
我不知道这是用于作业还是其他什么,但你基本上是从头开始编写功能组合 - 这是一种特殊的破坏性组合。
您似乎已经意识到了破坏性,因为您已将您的功能命名为x = queue.shift();
// we didn't get a value, queue must've been empty
if (x === undefined)
doSomething
// yay we got something, we can use x now
else
doOtherThing( x )
,但为了防止您不知道这是必要的,我会这样做在下面分享一个非破坏性的例子。
applyAndEmpty
&#13;
答案 1 :(得分:1)
您获得的undefined
来自此alert()
来电:
alert(applyAndEmpty(start, puzzlers));
在第二次迭代结束时,i
将为1
,队列长度为2
。因此,i
在下一次迭代中递增,并且循环条件不再成立 - i
为2,并且不再小于队列长度。
调试包含一些消息而不仅仅是值时,这是一个好习惯,这样你就可以告诉另一个调试输出行了。使用console.log()
代替alert()
也是个好主意。
答案 2 :(得分:1)
假设以下内容解决了您的问题。
var puzzlers = [
function(a) { return 8 * a - 10; },
function(a) { return (a - 3) * (a - 3) * (a - 3); },
function(a) { return a * a + 4; },
function(a) { return a % 5; }
];
var start = 2;
var applyAndEmpty = function(input, queue) {
for (var i = 0; i < queue.length; i++) {
if (i === 0) {
alert("hello 1");
var output = queue.shift()(input);
} else if (i === 1) {
alert("hello 2");
return queue.shift()(output);
} else {
alert("hello 3");
output = queue.shift()(output);
}
}
};
alert(applyAndEmpty(start, puzzlers));
&#13;