перерыв и некоторые, каждый
Лично нравится использоватьforEach
заменитьfor
цикл. Но иногда обнаруживается, что в процессе реализации необходимо использоватьbreak
.这时,一般又得切换回for
цикл. Например, встретите следующую логику:
let arr = [1, 2, 3, 4, 5]
let text = ''
for (let v of arr) {
if (v === 3) {
break
}
text += v + ','
}
console.log(text) // "1,2,"
смотреть сегоднястатьядумал, так какsome
Сама логика реализации замкнута накоротко, т.е. как только она возвращаетtrue
Последующие итерации больше не будут выполняться, так почему бы не использоватьsome
заменятьforEach
Шерстяная ткань?
let arr = [1, 2, 3, 4, 5]
let text = ''
arr.some(v => {
if (v === 3) {
return true
}
text += v + ','
})
console.log(text) // "1,2,"
Как правило, мы используемsome
Все используют его для возврата результатов. И эта практика не поднимать шума по поводу возвращаемого значения является сигналом чтения кода: оказалось, что это простое использование его цикла. Конечно, этот код не очень читабелен. Но он заменяетfor
прочь.
По аналогии,every
Он тоже короткозамкнутый, конечно, его тоже можно заменитьbreak
. Но убедитесь,break
предыдущая итерация возвращаетtrue
:
let arr = [1, 2, 3, 4, 5]
let text = ''
arr.every(v => {
if (v === 3) {
return
}
text += v + ','
return true
})
console.log(text) // "1,2,"
После того, как эта статья была размещена в кругу друзей, друзья сказали, что она не выглядит такой уж «чистой». Рекомендуется использоватьreduce
Реализация вне зависимости от производительности, в конце концов, пустая итерация не тратит много производительности. Если вы хотите заменитьbreak
логика, то вы должны использовать некоторыеflag
добиться, например:
let arr = [1, 2, 3, 4, 5]
let text = arr.reduce(function(p, c) {
if (this.break) {
return p
}
// ...
if (c === 3) {
this.break = true
return p
}
return p + c + ','
}.bind({}), '')
console.log(text) // "1,2,"
Кроме того, насчет «чистого», если он инкапсулирован в функцию, то он чистый:
function formatter(arr) {
let text = ''
arr.some(v => {
if (v === 3) {
return true
}
text += v + ','
})
return text
}
let arr = [1, 2, 3, 4, 5]
console.log(formatter(arr)) // "1,2,"
Есть также пользователи сети, оставляющие сообщение, что можно сделать рекурсивным способом.for
Сам цикл можно заменить рекурсией. и вообщеbreak
Условие, которое является рекурсивным выходом. Например, рекурсивная реализация этого примера:
function formatter(arr, text = '', i = 0) {
if (arr.length == 0 || arr[i] == '3') {
return text
}
text += arr[i] + ','
return formatter(arr, text, ++i)
}
let arr = [1, 2, 3, 4, 5]
console.log(formatter(arr)) // "1,2,"
продолжить и вернуться
Что касаетсяcontinue
Хорошо. . .
let arr = [1, 2, 3, 4, 5]
let text = ''
for (let v of arr) {
if (v === 3) {
continue
}
text += v + ','
}
console.log(text) // "1,2,4,5,"
Ответ на удивление прост,forEach
непосредственныйreturn
Достаточно:
let arr = [1, 2, 3, 4, 5]
let text = ''
arr.forEach(v => {
if (v === 3) {
return
}
text += v + ','
})
console.log(text) // "1,2,4,5,"
еслиcontinue
а такжеbreak
существуют одновременно? Например:
let arr = [1, 2, 3, 4, 5]
let text = ''
for (let v of arr) {
if (v === 2) {
continue
}
if (v === 4) {
break
}
text += v + ','
}
console.log(text) // "1,3,"
просто используйтеsome
В любом случае это хорошо, эти API массива по сути всеfor
цикл.
let arr = [1, 2, 3, 4, 5]
let text = ''
arr.some(v => {
if (v === 2) {
return
}
if (v === 4) {
return true
}
text += v + ','
})
console.log(text) // "1,3,"
Некоторым и каждому нужно обратить внимание
some
Функция используется для определения того, есть ли в массиве хотя бы один элемент, удовлетворяющий условиям функции обратного вызова. В это время функцию обратного вызова можно назвать функцией-предикатом (то есть смысл судить о том, является она или нет).Спецификациясерединаsome
Это реализовано так:
Нажмите, чтобы развернуть
- Let O be the result of calling ToObject passing the this value as the argument.
- Let lenValue be the result of calling the [[Get]] internal method of O with the argument
"length"
. - Let len be ToUint32(lenValue).
- If IsCallable(callbackfn) is false, throw a TypeError exception.
- If thisArg was supplied, let T be thisArg; else let T be undefined.
- Let k be 0.
- Repeat, while k < len
- Let Pk be ToString(k).
- Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
- If kPresent is true, then
- Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
- Let testResult be the result of calling the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
- If ToBoolean(testResult) is true, return true.
- Increase k by 1.
- Return false.
При моделировании с помощью JS основная логика выглядит следующим образом:
Array.prototype.some = function(callbackfn, thisArg) {
let len = Number(this.length)
let k = 0;
while(k < len) {
let Pk = String(k)
if (Pk in this) {
let kValue = this[Pk]
if (callbackfn.call(thisArg, kValue, k, this)) {
return true
}
}
k++
}
return false
}
Видно, что возвращаемое значение обратного вызова равноtrue
Если это так, функция возвращается напрямую и завершается. Это алгоритм короткого замыкания, не все обратные вызовы выполняются один раз, а затем окончательно вычисляются все значения AND.every
Аналогично, но наоборот, возвращаемое значение обратного вызова равноfalse
, целое возвращается напрямуюfalse
.
С точки зрения семантики, выраженной в реализации,some
говорит:Есть успех, у меня получится,а такжеevery
говорит:Если один терпит неудачу, я терплю неудачу.
Кроме того, следует подчеркнуть, что для разреженных массивов функция обратного вызова не выполняется, когда значение индекса не существует. Например, функция обратного вызова в следующем примере выполняется только 3 раза (аналогично другим API).
let arr = [1, 2, 3]
delete arr[1]
arr[5] = 6
console.log("1" in arr) // false
console.log(arr) // [1, empty, 3, empty × 2, 6]
arr.some(v => {
console.log(v) // 1 3 6
})
Таким образом, пустой массив, как бы ни была написана функция обратного вызова, результат все равноfalse
:
[].some(_ => true) // false
Эта статья закончилась.