0

I have the following method:

var items = [1,2,3];
$.map(items, function (item) {
  if (item === 1) {
    items.push(4);
  }
  console.log(item);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>

and I expect in console 1,2,3,4, but see 1,2,3. I mean I want to see one extra loop item.

Can I resolve it somehow? And if yes, how can I resolve it?

A. Gladkiy
  • 3,134
  • 5
  • 38
  • 82
  • you have log wrong array instead of `item` use this `console.log(items);` this will give expect output. – Narendra Jadhav Aug 31 '18 at 05:52
  • 3
    `.map()` stores the original length of the array before invoking the callback ([step 2](https://www.ecma-international.org/ecma-262/9.0/index.html#sec-array.prototype.map)). By design, it won't continue into *new* elements added during iteration. – Jonathan Lonowski Aug 31 '18 at 05:54
  • Agreed with @JonathanLonowski – Alive to die - Anant Aug 31 '18 at 05:55
  • `console.log(item);` needs to be `console.log(items);`. Seems TYPO mistake to me – Alive to die - Anant Aug 31 '18 at 05:56
  • @JonathanLonowski Maybe I can use something instead `.map()` for this? – A. Gladkiy Aug 31 '18 at 05:56
  • For such a think why don't you use native JS script? Is as simple as that: `var newItems = items.map( function( item ) { if ( item === 1 ) { items.push(4); } return item; } );` And keep in mind, the native `map` function it returns a new array, not the same you used as input. – KodeFor.Me Aug 31 '18 at 06:01
  • `map()` is a transformation of an array into an equivalent array with different values. If you need to add different logic to the array, you should use `forEach`. Or, in the jQuery case, `$.each()`. Or better, the plain `for` loop will work very well – Roberto Maldonado Aug 31 '18 at 06:04

3 Answers3

2

Iterator methods, like .map() or .forEach(), will prevent visiting elements added during iteration by using only the original length.

To avoid that, you'll want to use a standard loop, such as for..of (with the default array iterator checking length as it progresses):

var items = [1, 2, 3];

for (var item of items) {
  if (item === 1) {
    items.push(4);
  }
  
  console.log(item);
}

Though, other types of loops can be used to do the same.

Of course, beyond this current example, be careful that the loop doesn't become infinite from there always being new elements to iterate to next.

Jonathan Lonowski
  • 121,453
  • 34
  • 200
  • 199
1

Yes certainly you can resolve it, but in your specific case, items is passed by value to your map function so that you won't accidentally alter the original variable. The purpose of map is not for what you are using, but for mapping by specific key for an object or associative array. You should fall back to for loop or some other method for getting your desired output.

var items = [1, 2, 3];
for (var i = 0; i < items.length; i++) {
  const item = items[i];
  if (item === 1) {
    items.push(4);
  }
  console.log(item);
};
Kiran Shakya
  • 2,521
  • 2
  • 24
  • 37
0

use forIn instead of forOf, because sometime forOf give an error (maybe forOf not supported older version of js )..

         var items = [1,2,3];
         var k;
         for (k in items){
           if(items[k] === 1){
            items.push(4);
            }
         }
         alert(items);
  • `for..of` loops are relatively new to the language (since 2015), but are [supported by all modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of#Browser_compatibility). Though, a basic `for` loop would be a better alternative. [With arrays, `for..in` loops behave different than is often expected.](https://stackoverflow.com/questions/500504/why-is-using-for-in-with-array-iteration-a-bad-idea) – Jonathan Lonowski Aug 31 '18 at 23:28