而这个“臭名昭著”的goto语句其实就是一个代码流程控制器,关於goto语句的详细内容这里不会详细说明。 然而 javascript 没有明显的goto语句,但从break语句和continue语句中,不难发现 javascript 中goto的影子。
这是因为break语句和continue语句允许接受由一个定义好的 label 名称,以进行代码跳转。
我们来看看 mdn 提供的实例代码。
复制代码 代码如下:
var i, j;
loop1:
for (i = 0; i < 3; i++) { //The first for statement is labeled "loop1"
loop2:
for (j = 0; j < 3; j++) { //The second for statement is labeled "loop2"
if (i == 1 && j == 1) {
continue loop1;
} else {
console.log("i = " + i + ", j = " + j);
}
}
}
// Output is:
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// Notice how it skips both "i = 1, j = 1" and "i = 1, j = 2"
在这段实例代码中,实现了两层循环,而在每层循环外都定义了一个label,用於之后的continue语句进行调用。
第一层循环在loop1的 label 中,也就是说在后面的程序中,如果在continue语句或break语句选择了loop1 label,就会跳出最外层循环。
第二层循环在顶层循环中的loop2的 label 中,若在continue语句或break语句中选择了loop2 label,就会回到顶层循环的循环体内。
通过使用循环控制语句,我们可以对原有的循环执行判断进行干涉,以至於可以构建出十分复杂的逻辑系统。 说句题外话,linux kernel 中有非常多的goto语句,至於为什麼还是能经常听到不要用goto语句之流的言论,就自己 google 吧。
5. 高级循环
5.1 展开循环
我们先来看看两段代码,你猜猜哪一个的性能更加。
复制代码 代码如下:
// Setup
var array = [
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"],
["DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA", "DATA"]
];
function process(item) {
// Do something with item
}
// Case 1
for (var i = array.length - 1; i >= 0; i--) {
for (var j = array[i].length - 1; j >= 0; i--) {
process(array[i][j]);
}
}
// Case 2
for (var i = array.length - 1; i >= 0; i = i - 4) {
for (var j = array[i].length - 1; j >= 0; j = j - 6) {
process(array[i][j]);
process(array[i][j - 1]);
process(array[i][j - 2]);
process(array[i][j - 3]);
process(array[i][j - 4]);
process(array[i][j - 5]);
}
for (var j = array[i - 1].length - 1; j >= 0; j = j - 6) {
process(array[i][j]);
process(array[i][j - 1]);
process(array[i][j - 2]);
process(array[i][j - 3]);
process(array[i][j - 4]);
process(array[i][j - 5]);
}
for (var j = array[i - 2].length - 1; j >= 0; j = j - 6) {
process(array[i][j]);
process(array[i][j - 1]);
process(array[i][j - 2]);
process(array[i][j - 3]);
process(array[i][j - 4]);
process(array[i][j - 5]);
}
for (var j = array[i - 3].length - 1; j >= 0; j = j - 6) {
process(array[i][j]);
process(array[i][j - 1]);
process(array[i][j - 2]);
process(array[i][j - 3]);
process(array[i][j - 4]);
process(array[i][j - 5]);
}
}
我需要对array中的所有子数组的元素进行历遍,有两种方案,一种是我们平常所使用的方法,另一种是把循环任务展开。 答案是 case 2 性能更好,因为在每 6 个元素之间的执行判断都全部删除了,自然比往常的都要快。