больше не прерывайся и продолжай

JavaScript

перерыв и некоторые, каждый

Лично нравится использовать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Это реализовано так:

Нажмите, чтобы развернуть
  1. Let O be the result of calling ToObject passing the this value as the argument.
  2. Let lenValue be the result of calling the [[Get]] internal method of O with the argument "length".
  3. Let len be ToUint32(lenValue).
  4. If IsCallable(callbackfn) is false, throw a TypeError exception.
  5. If thisArg was supplied, let T be thisArg; else let T be undefined.
  6. Let k be 0.
  7. Repeat, while k < len
    1. Let Pk be ToString(k).
    2. Let kPresent be the result of calling the [[HasProperty]] internal method of O with argument Pk.
    3. If kPresent is true, then
      1. Let kValue be the result of calling the [[Get]] internal method of O with argument Pk.
      2. 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.
      3. If ToBoolean(testResult) is true, return true.
    4. Increase k by 1.
  8. 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

Эта статья закончилась.