skip to Main Content

From the docs I’ve been reading, the following ought to create an Array from the keys of a Map:

var m = new Map();
m.set("a", 1);
m.set("b", 2);

var arr1 = Array.from(m.keys());
var arr2 = Array.from(m.values());

console.log(arr1.length);
console.log(arr2.length);

I’d expect that to print 2 for both arrays, but in reality both arrays are empty and it prints 0. What gives?

Edit: This issue seems to occur on a specific webpage when I execute the above code in the Javascript console. If I execute it on other pages it works as expected.

Edit 2: Upon further investigation, it appears that the page in question is including prototype.js v1.6.1 which is somehow causing Array.from to break.

2

Answers


  1. Chosen as BEST ANSWER

    This appears to be caused by a known bug in prototype.js. See this GitHub issue "Native Array.from is overwritten by $A which is not able to handle all cases used by the native function #338".

    An excerpt from the issue:

    From the definition of these two functions: The Array.from() method creates a new Array instance from an array-like or iterable object. However, the $A function only accepts an array-like collection (anything with numeric indices). So $A is not able to handle other iterable objects without numeric indices such as MapIterator.

    When $A try to create a new array by reading the iterable.length which does exist in some native iterable objects such as MapIterator, the result will be an array with length 0 returned back.


  2. What you’re encountering is due to a conflict with the prototype.js
    library. As@Bri Bri mentioned.

    In your case prototype.js is overriding or interfering with the native Array.from method, since because of that it malfunctions. This can result in Array.from not working as expected and not delivering the result expected, leading to empty arrays when trying to convert the keys and values of the Map object.

    To avoid this issue and as a work around use Array Spread operator.

    Using spread operator :

    var m = new Map();
    m.set("a", 1);
    m.set("b", 2);
    
    var arr1 = [...m.keys()];
    var arr2 = [...m.values()];
    
    console.log("Keys :"+JSON.stringify(arr1.length)); // 2
    console.log("Values :"+JSON.stringify(arr2.length)); // 2

    Using slice:

    var m = new Map();
    m.set("a", 1);
    m.set("b", 2);
    
    function arrayFrom(iterable) {
      return [].slice.call(iterable);
    }
    
    function arrayFromPolyfill(iterable) {
      if (typeof Array.from === 'function') {
        return Array.from(iterable);
      }
      return [].slice.call(iterable);
    }
    
    var arr1 = arrayFromPolyfill(m.keys());
    var arr2 = arrayFromPolyfill(m.values());
    
    console.log("Keys :"+JSON.stringify(arr1.length)); // 2
    console.log("Values :"+JSON.stringify(arr2.length)); // 2
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search