面试:你能终止JS的forEach循环吗?
3种方法终止forEach循环
Photo by 傅甬 华
面试官: 你能终止JS的forEach循环吗? 这个问题我曾经在我的一次面试中被问过, 我的答案是 “不,我不能”
很不幸, 我的回答让面试官结束了这场面试。
这个结果很沮丧, 我问面试官, “为什么?真的有可能终止JS的forEach循环吗?”
在面试官回答之前,我解释了我的理解,为什么不能直接停止JS的forEach循环。
我的回答是正确的吗?
朋友们,你们觉得下面的代码会输出什么数字?
是输出一个呢?还是多个?
const array = [ -3, -2, -1, 0, 1, 2, 3 ]
array.forEach((it) => {
if (it >= 0) {
console.log(it)
return // 或者 break
}
})
是的,它会输出 ‘0’, ‘1’, ‘2’, ‘3’.
没错! 我把代码展示给面试官看, 但是他仍然坚定有办法终止JS的forEach循环。
Photo by Christian Erfurt
为什么?
为了说服他, 我不得不手动模拟实现一个 forEach
循环。
Array.prototype.forEach2 = function (callback, thisCtx) {
if (typeof callback !== 'function') {
throw `${callback} is not a function`
}
const length = this.length
console.log('length>>>', length)
let i = 0
while (i < length) {
if (this.hasOwnProperty(i)) {
// 关键在这里,每一个循环语句都会在这里被直接执行
console.log('i>>>', i, this[i])
callback.call(thisCtx, this[i], i, this)
}
i++
}
}
当我们用forEach去遍历一个数组的时候, 回调函数会立即执行数组里的每一个元素, 没有任何办法去打断执行。 为什么"break"或者"return"语句在这里就不生效呢?
很简单的例子,在下面的代码里,即使 ‘func1’ 遇到 'return' 语句, ‘2’ 也会被输出到控制台。
const func1 = () => {
console.log(1)
return
}
const func2 = () => {
func1()
console.log(2)
}
func2()
所以对于上面模拟的forEach循环来说,while内部执行的回调函数,即使回调函数里有"return"语句,也只是影响回调函数的执行,不会影响代码继续往下执行。
3种方法终止forEach循环
你很棒, 但是我要告诉你我们至少有3种方法终止forEach循环.
1. 抛出一个错误
当找到第一个大于等于的数字,这段代码就不会继续执行。所以只会打印输出0
const array = [ -3, -2, -1, 0, 1, 2, 3 ]
try {
array.forEach((it) => {
if (it >= 0) {
console.log(it)
throw Error(`We've found the target element.`)
}
})
} catch (err) {
}
卧槽,还真的终止了···
2. 设置数组长度为0
不要惊讶,这是面试官告诉我的方法。
我们也可以通过设置数组长度为0终止forEach。正如你所知的那样,数组长度为0,forEach不会执行任何回调。
const array = [ -3, -2, -1, 0, 1, 2, 3 ]
array.forEach((it) => {
if (it >= 0) {
console.log(it)
array.length = 0
}
})
3. 用splice方法去除数组元素
类似于方法2,你可以删除目标值后面的所有元素,然后forEach将会自动停止。
const array = [ -3, -2, -1, 0, 1, 2, 3 ]
array.forEach((it, i) => {
if (it >= 0) {
console.log(it)
array.splice(i + 1, array.length - i)
}
})
注意
虽然用改变数组长度的方法,回调函数“貌似”不再执行,但是其实forEach内部的while循环还会继续执行,因为while循环次数在一开始就确定下来了,只是改变了数组,导致或者不到元素了。
建议:请使用for循环或者some方法
我对面试官说, “可能你是对的,虽然你成功终止了forEach循环, 但是我想你的老板会炒了你的鱿鱼,因为这真的是一段很糟糕的代码。我不喜欢写这样的代码,同事们会恨死我”
我们可以用 for
or some
方法来解决。
1. for
const array = [ -3, -2, -1, 0, 1, 2, 3 ]
for (let i = 0, len = array.length; i < len; i++) {
if (array[i] >= 0) {
console.log(array[i])
break
}
}
2. some
const array = [ -3, -2, -1, 0, 1, 2, 3 ]
array.some((it, i) => {
if (it >= 0) {
console.log(it)
return true
}
})
结束语
尽管面试官以这个问题结束了面试,但是我很高兴,我不用加入这个公司,不用写这一坨屎一样的代码。真的是依托答辩。