Массив короткого замыкания.по каждому элементу как назвать перерыва



[1,2,3].forEach(function(el) {
if(el === 1) break;
});


как я могу сделать это с помощью новой forEach метод в JavaScript? Я пробовал return;,return false; и break. break ДТП и return не делает ничего, кроме продолжения итерации.

520   28  

28 ответов:

там нет встроенной способности break на forEach. Чтобы прервать выполнение, вам нужно будет создать какое-то исключение. например.

var BreakException = {};

try {
  [1, 2, 3].forEach(function(el) {
    console.log(el);
    if (el === 2) throw BreakException;
  });
} catch (e) {
  if (e !== BreakException) throw e;
}

исключения JavaScript не очень красиво. Традиционный for цикл может быть более подходящим, если вам действительно нужно break внутри него.

использовать Array#some

вместо этого используйте Array#some:

[1, 2, 3].some(function(el) {
  console.log(el);
  return el === 2;
});

это работает, потому что some возвращает true как только любой из обратных вызовов, выполненных в порядке массива, возвращает true, короткое замыкание исполнения остальных.

some, его инверсный every (который остановится на return false), и forEach все методы пятого издания ECMAScript, которые необходимо будет добавить в Array.prototype в браузерах, где они отсутствуют.

теперь есть еще лучший способ сделать это в ECMAScript2015 (он же ES6) с помощью нового для петли. Например, этот код не выводит элементы массива после числа 5:

let arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (let el of arr) {
  console.log(el);
  if (el === 5) {
    break;
  }
}

документы:

оба for...in и для...из операторы перебирают что-то. Основное различие между ними заключается в том, что они перебирать. The for...in оператор выполняет итерацию по перечисляемым свойствам объекта в исходном порядке вставки. Элемент для...из оператор перебирает данные, которые итерационный объект определяет для повторения.

нужен индекс в итерации? Вы можете использовать Array.entries():

for (const [index, el] of arr.entries()) {
  if ( index === 5 ) break;
}

можно использовать способ:

[1,2,3].every(function(el) {
    return !(el === 1);
});

для старой поддержки браузера используйте:

if (!Array.prototype.every)
{
  Array.prototype.every = function(fun /*, thisp*/)
  {
    var len = this.length;
    if (typeof fun != "function")
      throw new TypeError();

    var thisp = arguments[1];
    for (var i = 0; i < len; i++)
    {
      if (i in this &&
          !fun.call(thisp, this[i], i, this))
        return false;
    }

    return true;
  };
}

более подробная информация здесь.

слово MDN документация Array.prototype.forEach():

здесь нет способа остановить или сломать a forEach() цикл, отличный от выдавая исключение. Если вам нужно такое поведение,.forEach() метод неправильный инструмент, вместо этого используйте простой цикл. Если вы тестируете элементы массива для предиката и вам нужно логическое возвращаемое значение, вы можете использовать every() или some() вместо.

для вашего кода (в вопросе), как предложил @bobince, используйте Array.prototype.some() вместо. Он очень хорошо подходит к вашей usecase.

Array.prototype.some() выполняет функцию обратного вызова один раз для каждого элемента, присутствующего в массиве, пока не найдет тот, где обратный вызов возвращает истинное значение (значение, которое становится истинным при преобразовании в Boolean). Если такой элемент найден, some() немедленно возвращает true. В противном случае, some() возвращает false. обратный вызов вызывается только для индексов массива, которым присвоены значения; он не вызывается для индексов, которые были удалены или которым никогда не присваивались значения.

к сожалению в этом случае это будет гораздо лучше, если вы не используете forEach. Вместо этого используйте обычный for петли и теперь он будет работать именно так, как вы ожидаете.

var array = [1, 2, 3];
for (var i = 0; i < array.length; i++) {
  if (array[i] === 1){
    break;
  }
}

использовать jquery ' s each метод, так как он позволяет возвращать false внутри функции обратного вызова:

$.each(function(e, i) { 
   if (i % 2) return false;
   console.log(e)
})

библиотеки Lodash также предоставляет takeWhile метод, который можно связать с картой / уменьшить / сложить и т. д.:

var users = [
  { 'user': 'barney',  'active': false },
  { 'user': 'fred',    'active': false },
  { 'user': 'pebbles', 'active': true }
];

_.takeWhile(users, function(o) { return !o.active; });
// => objects for ['barney', 'fred']

// The `_.matches` iteratee shorthand.
_.takeWhile(users, { 'user': 'barney', 'active': false });
// => objects for ['barney']

// The `_.matchesProperty` iteratee shorthand.
_.takeWhile(users, ['active', false]);
// => objects for ['barney', 'fred']

// The `_.property` iteratee shorthand.
_.takeWhile(users, 'active');
// => []

Если вы хотите использовать предложение декана Эдварда и бросьте ошибку StopIteration, чтобы вырваться из цикла без необходимости ловить ошибку, вы можете использовать следующую функцию (изначально отсюда):

// Use a closure to prevent the global namespace from be polluted.
(function() {
  // Define StopIteration as part of the global scope if it
  // isn't already defined.
  if(typeof StopIteration == "undefined") {
    StopIteration = new Error("StopIteration");
  }

  // The original version of Array.prototype.forEach.
  var oldForEach = Array.prototype.forEach;

  // If forEach actually exists, define forEach so you can
  // break out of it by throwing StopIteration.  Allow
  // other errors will be thrown as normal.
  if(oldForEach) {
    Array.prototype.forEach = function() {
      try {
        oldForEach.apply(this, [].slice.call(arguments, 0));
      }
      catch(e) {
        if(e !== StopIteration) {
          throw e;
        }
      }
    };
  }
})();

приведенный выше код даст вам возможность запускать код, такой как следующий, без необходимости делать свои собственные предложения try-catch:

// Show the contents until you get to "2".
[0,1,2,3,4].forEach(function(val) {
  if(val == 2)
    throw StopIteration;
  alert(val);
});

одна важная вещь, чтобы помнить, что это только обновление Матрица.прототип.функция forEach, если она уже существует. Если он еще не существует, он не будет изменять его.

из вашего примера кода, это выглядит как Array.prototype.find это то, что вы ищете: массив.прототип.найти() и массив.прототип.findIndex()

[1, 2, 3].find(function(el) {
    return el === 2;
}); // returns 2

короткий ответ: используйте for...break для этого или измените свой код, чтобы избежать взлома forEach. Не используйте .some() или .every() эмуляция for...break. Перепишите свой код, чтобы избежать for...break петли, или использовать for...break. Каждый раз, когда вы используете эти методы как for...break альтернативный Бог убивает котенка.

ответ:

.some() и .every() как вернуть boolean значение .some() возвращает true если есть какой-либо элемент, для которого переданная функция возвращает true, все возвращается false если есть какой-либо элемент, для которого переданная функция возвращает false. Вот что означают эти функции. Использование функций для того, что они не означают, намного хуже, чем использование таблиц для макета вместо CSS, потому что это расстраивает всех, кто читает ваш код.

кроме того, единственный возможный способ использовать эти методы как for...break альтернатива состоит в том, чтобы сделать побочные эффекты (изменить некоторые vars за пределами .some() функция обратного вызова), и это не сильно отличается от for...break.

Итак, используя .some() или .every() как for...break альтернатива петли не свободна от побочных эффектов, это не намного чище, чем for...break, это расстраивает, так что это не лучше.

вы всегда можете переписать свой код так, что не будет необходимости в for...break. Вы можете фильтровать массив с помощью .filter(), вы можете разделить массив с помощью .slice() и так далее, а затем использовать .forEach() или .map() для этой части массива.

нашел это решение на другом сайте. Вы можете обернуть forEach в сценарии try / catch.

if(typeof StopIteration == "undefined") {
 StopIteration = new Error("StopIteration");
}

try {
  [1,2,3].forEach(function(el){
    alert(el);
    if(el === 1) throw StopIteration;
  });
} catch(error) { if(error != StopIteration) throw error; }

подробнее здесь:http://dean.edwards.name/weblog/2006/07/enum/

Если вам не нужно обращаться к массиву после итерации вы можете выручить, установив длину массива в 0. Если он вам все еще нужен после итерации, вы можете клонировать его с помощью slice..

[1,3,4,5,6,7,8,244,3,5,2].forEach(function (item, index, arr) {
  if (index === 3) arr.length = 0;
});

или с клоном:

var x = [1,3,4,5,6,7,8,244,3,5,2];

x.slice().forEach(function (item, index, arr) {
  if (index === 3) arr.length = 0;
});

что является гораздо лучшим решением, чем выбрасывание случайных ошибок в коде.

это цикл for, но поддерживает ссылку на объект в цикле так же, как forEach (), но вы можете вырваться.

var arr = [1,2,3];
for (var i = 0, el; el = arr[i]; i++) {
    if(el === 1) break;
}

Это просто то, что я придумал, чтобы решить проблему... Я почти уверен, что это исправляет проблему, которую имел оригинальный asker:

Array.prototype.each = function(callback){
    if(!callback) return false;
    for(var i=0; i<this.length; i++){
        if(callback(this[i], i) == false) break;
    }
};

и тогда вы бы назвали его с помощью:

var myarray = [1,2,3];
myarray.each(function(item, index){
    // do something with the item
    // if(item != somecondition) return false; 
});

возврат false внутри функции обратного вызова приведет к перерыву. Дайте мне знать, если это на самом деле не работает.

Я использую nullhack для этой цели он пытается получить доступ к свойству null, что является ошибкой:

try {
  [1,2,3,4,5]
  .forEach(
    function ( val, idx, arr ) {
      if ( val == 3 ) null.NULLBREAK;
    }
  );
} catch (e) {
  // e <=> TypeError: null has no properties
}
//

еще одна концепция, которую я придумал:

function forEach(array, cb) {
  var breakOnNext = false;
  function _break() { breakOnNext = true; }
  for (var i = 0, bound = array.length; i < bound; ++i) {
    if (breakOnNext) { break; }
    cb(array[i], i, array, _break);
  }
}

использование:

forEach(['a','b','c','d'], function (e, i, array, _break) {
  console.log(e, i);
  if (e === 'b') { _break(); }
});

может потребоваться некоторая настройка, особенно для поддержки итерации свойств объекта.

если вы хотите сохранить ваш forEach синтаксис, это способ сохранить ее эффективной (хотя и не так хорошо как обычный цикл for). Немедленно проверьте переменную, которая знает, хотите ли вы выйти из цикла.

в этом примере используется анонимная функция для создания область действия функции вокруг forEach что нужно в магазине сделал информация.

(function(){
    var element = document.getElementById('printed-result');
    var done = false;
    [1,2,3,4].forEach(function(item){
        if(done){ return; }
        var text = document.createTextNode(item);
        element.appendChild(text);
        if (item === 2){
          done = true;
          return;
        }
    });
})();
<div id="printed-result"></div>

мои два цента.

Как упоминалось ранее, вы не можете сломать .forEach().

вот немного более современный способ выполнения foreach с помощью итераторов ES6. Позволяет получить прямой доступ к index/value при переборе.

const array = ['one', 'two', 'three'];

for (const [index, val] of array.entries()) {
  console.log('item:', { index, val });
  if (index === 1) {
    console.log('break!');
    break;
  }
}

выход:

item: { index: 0, val: 'one' }
item: { index: 1, val: 'two' }
break!

ссылки

использовать array.prototype.every функция, которая предоставляет вам утилиту для разрыва цикла. Смотрите пример здесь документация Javascript на Mozilla developer network

согласен с @bobince, голосуют.

кроме того, FYI:

прототип.js имеет что-то для этой цели:

<script type="text/javascript">
  $$('a').each(function(el, idx) {
    if ( /* break condition */ ) throw $break;
    // do something
  });
</script>

$break будет пойман и обработан прототипом.JS внутренне, нарушая" каждый " цикл, но не создавая внешних ошибок.

посмотреть прототип.JS API для сведения.

jQuery также имеет способ, просто верните false в обработчике, чтобы прервать цикл рано:

<script type="text/javascript">
  jQuery('a').each( function(idx) {
    if ( /* break condition */ ) return false;
    // do something

  });
</script>

посмотреть jQuery API для сведения.

Это не самый эффективный, так как вы все еще цикл все элементы, но я подумал, что это может быть стоит рассмотреть очень простой:

let keepGoing = true;
things.forEach( (thing) => {
  if (noMore) keepGoing = false;
  if (keepGoing) {
     // do things with thing
  }
});

вы можете следовать ниже, который работает для меня код:

 var     loopStop = false;
YOUR_ARRAY.forEach(function loop(){
    if(loopStop){ return; }
    if(condition){ loopStop = true; }
});

Я знаю, что это не правильный путь. Это не разорвать петлю. Это-Jugad

let result = true;
[1, 2, 3].forEach(function(el) {
    if(result){
      console.log(el);
      if (el === 2){
        result = false;
      }
    }
});

Я предпочитаю использовать for in

var words = ['a', 'b', 'c'];
var text = '';
for (x in words) {
    if (words[x] == 'b') continue;
    text += words[x];
}
console.log(text);

for in работает forEach, и вы можете добавить возврат к функции выхода внутри. Лучшая производительность тоже.

Если вам нужно разбить на основе значения элементов, которые уже находятся в вашем массиве, как в вашем случае (т. е. если условие разбиения не зависит от переменной времени выполнения, которая может измениться после присвоения массиву его значений элементов), вы также можете использовать комбинацию slice () и indexOf () следующим образом.

Если вам нужно сломать, когда forEach достигает 'Apple', вы можете использовать

var fruits = ["Banana", "Orange", "Lemon", "Apple", "Mango"];
var fruitsToLoop = fruits.slice(0, fruits.indexOf("Apple"));
// fruitsToLoop = Banana,Orange,Lemon

fruitsToLoop.forEach(function(el) {
    // no need to break
});

Как заявил in W3Schools.com Метод slice() возвращает выбранные элементы в массиве, как новый объект массива. Исходный массив не изменяется.

посмотреть его в JSFiddle

надеюсь, что это поможет кому-то.

попробуйте "найти" :

var myCategories = [
 {category: "start", name: "Start", color: "#AC193D"},
 {category: "action", name: "Action", color: "#8C0095"},
 {category: "exit", name: "Exit", color: "#008A00"}
];

function findCategory(category) {
  return myCategories.find(function(element) {
    return element.category === category;
  });
}

console.log(findCategory("start"));
// output: { category: "start", name: "Start", color: "#AC193D" }

правильный ответ зависит от почему вы хотите сделать это.

если то, что вы хотите:"как чистый и лаконичный способ вырваться из forEach() как это возможно, учитывая, что break не допускается" затем вы можете переопределить массив.еогеасп (), чтобы позволить вам сделать это:

[1,2,3,4,5].forEach((x,i,stop) => { // x and i are the standard 2 args
  if (x > 3) {
    stop() // You could call it 'end', 'brk' or whatever...
  }
  console.log(x)
})

вот переопределение, обратите внимание, что forEach() обычно передает два параметра: текущий итерированный объект и индекс. Мы просто добавляем третье:

Array.prototype.forEach = function(fn) {
  var StopIteration = new Error("StopIteration");
  var len = this.length;
  function stop() {
    throw StopIteration;
  }
  for (i=0;i<len;i++) {
    try {
      fn(this[i], i, stop)
    } 
    catch(e) {
      if(e == StopIteration) {
        return
      }
      throw e;
    }
  }
}

вы можете использовать любое имя, которое вам нравится (кроме break, или любое другое зарезервированное ключевое слово, вот не повезло!)

(на реальном проекте вы должны пойти с одним из супер-повышенных ответов. Я просто добавляю это, потому что некоторые люди могут найти эту концепцию полезной в других приложениях).

еще один подход

        var wageType = types.filter(function(element){
            if(e.params.data.text == element.name){ 
                return element;
            }
        });
        console.dir(wageType);
var Book = {"Titles":[                          
    {
    "Book3" : "BULLETIN 3"
    }   
    ,
    {
    "Book1" : "BULLETIN 1"
    }
    ,
    {
    "Book2" : "BULLETIN 2"
    }    
]}

var findbystr = function(str) { 
    var return_val;
    Book.Titles.forEach(function(data){ 
        if(typeof data[str] != 'undefined')
        {
            return_val = data[str];
        } 
    }, str) 

    return return_val;
}

book = findbystr('Book1');
console.log(book);

Comments

    Ничего не найдено.