Generate a series of whole numbers using the spread operator

Although there is no direct equivalent to Python 3's range in ES6, there are several workarounds available. I am curious about the effectiveness of one specific workaround that actually works. Take this example:

[...Array(10).keys()];

The reason why this workaround functions as intended is somewhat mysterious because Array(10).keys() seems empty at first glance.

I acknowledge that many common workarounds can be inefficient as they create unnecessary arrays. By utilizing a generator function, it is possible to avoid this issue without creating extra arrays. For instance:

[...(function*(){let i = 0; while(i<10) yield i++;})()];

The main focus of my question lies in understanding why the initial workaround yields the desired result.

Edit:

Based on responses, some suggest that evaluating Array(10) is the same as evaluating Array.apply(null,Array(10)), but they differ. For example, .hasOwnProperty(0) returns

false</code for the former and <code>true
for the latter. I am willing to consider arguments that they are somehow equivalent in ways relevant to this context since my understanding is clearly lacking. It appears that iterating over keys is influenced by the shared length property rather than defined array indexes. If this behavior is standard, I would like clarification on that aspect.

Answer №1

Array#keys retrieves an Array iterator. The spread syntax then exhausts the iterator by accessing each value until there are none left, collecting all values and spreading them into a new array.

Array(10) creates an array exotic object without integer-indexed keys, only a length property. Despite appearing 'empty', Array(10).keys() is not. The use of Array#keys doesn't rely on actual elements but rather on the length property. The function CreateArrayIterator generates an iterator using the intrinsic object %ArrayIteratorPrototype%. By continuously incrementing until reaching the array's length, Array#keys constructs an iterator for all keys in the array, even if no integer keys were present initially.


To delve into the abstract steps, refer to Section 12.2.5.2 ArrayAcculumation of the ECMAScript Language Specification, focusing on the

SpreadElement : ... AssignmentExpression
production, illustrating the process of iterating through an iterator alongside spread syntax.

For details on gathering values into a new array, check out Section 12.2.5.3 Evaluation. Specifically, the ArrayLiteral : [ ElementList ] production encompasses the process that [...Array.keys()] undergoes. Through ArrayAcculumation, values from the iterator are collected and placed into the new array.

Answer №2

Array.prototype.keys function returns a new Array Iterator.
Array(10) represents an array with 10 empty slots.

When you spread the keys of the array, you are iterating over it and creating a new array where each item corresponds to the slots in the original array.

This can be observed using a for of loop:

const arr = Array(10).keys();
for (let key of arr) {
  console.log(key);
}

Alternatively, you can achieve the same result by using Array.from along with a mapping function:

const arr = Array.from(Array(10), (_, idx) => idx);
console.log(arr);

Edit
Following your question edit regarding the result of Array(10):
According to the documentation:

If only an integer between 0 and 2^32-1 is passed as argument to the Array constructor, it creates a new JavaScript array with its length property set to that number (Note: this results in an array of arrayLength empty slots, not undefined values). Passing any other number will throw a RangeError exception.

In summary:

  • A new array is created
  • The length property is set to the provided number

  • You get empty slots equal to the provided number

Using .keys on this array generates an Iterator where each slot index is returned as a value.
For example:

let it = Array(10).keys();  

Calling:

it.next();

Will return:

{value: 0, done: false}  

Subsequent calls will produce

{value: n, done: false}

until reaching the last slot:

{value: 9, done: false}

after which, the next .next call results in:

{value: undefined, done: true} 

indicating the end of iterations.

Example execution:

const it = Array(10).keys();
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next()); // done: true

Answer №3

Array(10) will generate a new array with a length of 10, where each element is initially set to undefined.

The method Array(10).keys() will produce an iterator that loops through the keys of the array, which are the numbers from 0 to 9.

Using the spread syntax in JavaScript for defining array literals (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_operator) allows for full iteration of any given iterator and adds the results from the iterator to the newly created array in sequential order.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Using Handlebars to incorporate altered ajax information into a template

Currently, I am exploring ways to utilize manipulated data from an ajax request in conjunction with Handlebars. Within my database, the data is stored as an object like so: {"1 year":"$4.95", "2 years":"$3.95"} My objective now is to make use of this d ...

Any tips on making Angular 8's sort table function seamlessly integrate with data retrieved from Firebase?

I am currently working on an angular PWA project that utilizes a material table to display data from Firebase. The data is being shown properly and the paginator is functioning as expected. However, I am facing an issue with sorting the data using mat-sort ...

Struggling to set the value for a variable within an Angular factory?

When dealing with a variable as an array, I have no trouble pushing objects inside and retrieving the values within the controller. However, when trying to directly assign an object to that variable, I run into issues. If anyone can assist me in achieving ...

Modifying elements within a JSON array-generated list

As a beginner in JavaScript, I have encountered an issue with my code. It dynamically creates a list from a JSON array called rolesData and displays the data from "roles" in a list based on a random selection (using document.body.appendChild(createList(rol ...

What could be causing my code to fail in the useEffect hook every time I make updates to my JSON

I have a function that receives JSON data from the server. Using the {jsonData.map((element) => renderComponents(element, jsonData))} function, I loop through the data and send each object to the renderComponents function along with the full JSON data. ...

Understanding the application of JSON data can be simplified by following these

I am looking to manipulate dates by either adding or subtracting them, but I am unsure of how to extract the dates from the other data present. var fetch = require('node-fetch'); fetch('https://api.nasa.gov/planetary/earth/assets?lon=100.7 ...

Modify the h:outputText value dynamically with the power of jQuery!

Is it possible to use jQuery to dynamically change the value of my OutputText component? This is the code snippet for my component: <h:outputText id="txt_pay_days" value="0" binding="#{Attendance_Calculation.txt_pay_days}"/> I would apprecia ...

Trigger a notification from one webpage to another (PHP, JavaScript, HTML)

I'm currently working on a website that consists of both a receptionist page and a user page with multiple logins. The receptionist page displays a table listing all logged-in users, including their status (either ready or busy). This table is refresh ...

Learn how to utilize Vue 3 to access properties that have been passed down from a parent component, even if they

Hey there, hope everything is going well. I'm familiar with react.js, but when I gave vue a try, things felt a bit different. In react, it's easy to access props passed from the parent in the child component without much hassle. However, in vue, ...

Here is a method for arranging a collection of files based on matching keywords in their filenames

I need help refining my sort function for scanning a directory and listing only jpg files that contain a specific keyword in their file name. For instance, I want to filter and arrange all jpg files with filenames that have the term "toys". $a_img[] = ...

Best practices for refreshing FullCalendar v4 after updating the events object using AJAX calls

Utilizing fullcalendar V4 to display events. The events load normally, but I am in need of adding a filter using multiple checkboxes and refreshing the fullcalendar events after a checkbox is changed with AJAX. After the change, I receive the new object e ...

Is there a way to access a variable declared in index.js from a controller?

Currently, I am experimenting with forms-angular (). In my index.js file, I have defined a variable called DataFormHandler. However, I am facing an issue trying to access this variable in my controllers. The setter app.set("formHandler", DataFormHandler) ...

Guidelines on maintaining an active getSelection with JavaScript

I need help figuring out how to change the font size of selected text within a div without losing the highlight/selection when I click a button. Can someone assist me in keeping the text highlighted while also resizing it upon clicking the button? ...

What is the best way to trigger a JavaScript function whenever a field reaches a specific length?

I need to update a function that currently triggers when the user clicks or tabs out of the employee_number field. My goal is for it to run whenever the length of the entered numbers reaches 6, without requiring the user to leave the field. When I attempte ...

Is there an Angular directive that can replicate a mouseenter event?

Is there a way to simulate a mouseenter event with a directive? I have been searching for a directive that can simulate a mouseenter event, but all I have found so far is one that binds a function to mouse over or karma tests for simulating mouse over. W ...

Setting a radio button dynamically based on JSON data by using a select dropdown option

I am looking to generate questions from a pre-selected list using Vue.js. I have successfully implemented this with a radio button that reveals a new set of questions once checked. Now, I want to achieve the same functionality using a dropdown selection. ...

Unable to activate the date range picker

I am having trouble with integrating the daterange picker on my webpage. I can't seem to get it to work properly. Can anyone help me figure out what I might be doing wrong or if there's something missing? CSHTML: <div class="has-feedback" &g ...

Retrieving a MAC address from a device using a web script or HTTP protocol

Is it feasible, with access to all end user devices, to request the device's MAC address using web scripting in Apache/IIS/Nginx? Would PHP, Perl, or ASP be able to accomplish this task? The client devices run on iOS, so the method described here wil ...

The Controller of Conversations

In the HTML code, there is a dialog element with an identification of divMyDialog1. This dialog is connected to a JavaScript class called MyDialog1. Each dialog has its own unique id and associated class name. MyDialog1 = function(divStr){ this.divStr ...

Developing play and pause capabilities using JavaScript for the existing audio player

Currently, I am developing a Chrome extension that includes an HTML popup with buttons to play audio files. However, I feel that my current approach is not the most efficient and I am struggling to find ways to simplify the process. The method I am using n ...