"Surprising results encountered when using the filter method in JavaScript Arrays

Scenario

During a recent job interview, I was given a coding test:


var array = [1, 2, 3];
array[10] = 10;

alert(array.filter( n => n === undefined));

I confidently expected the alert to show an array with 7x undefined values, or something similar.

To my surprise, it actually displayed an empty array with a length of 0.

Mystery

This outcome is quite puzzling to me. Can anyone shed light on why this result occurred?

Answer №1

Items that have been deleted or are uninitialized in sparse arrays will not be visited.

Array#forEach

Explanation

forEach() runs the provided callback function once for each element in the array, going through them in order from lowest index to highest. It doesn't run on indices that have been removed or are undefined (such as in sparse arrays).

var array = [1, 2, 3, , , , , , , , 10];

console.log(array.filter((n, i) => (console.log(i), n === undefined)));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Answer №2

If you need insight into how the internal workings of Array.prototype.filter (and other similar methods like forEach, map, reduce) operate, it can be summarized as follows (excluding boundary/corner checks):

Array.prototype.filter = function(fun/*, thisArg*/) {
    var arr = Object(this); 
    var len = arr.length;
    var res = [];

    for (var i = 0; i < len; i++) {
      if (i in arr) {
        var val = arr[i];

        if (fun.call(thisArg, val, i, arr)) {
          res.push(val);
        }
      }
    }

    return res;
}

An important aspect to note here is the if statement within the for loop:

if (i in arr) { ... }

This condition clearly indicates that in order for array items to be 'filterable', they must be explicitly declared or initialized with a corresponding key or property associated in the arr, which may not hold true for a sparse array as mentioned in another response.

note: If you execute

var array = [1, 2, 3]; array[10] = 10;
in the console, the resulting sparse array would look like this:

Array[11]
  0: 1
  1: 2
  2: 3
  10: 10
  length: 11
  __proto__: Array[0]

Answer №3

The arrow function you are using as a filter is only returning undefined items, but none of your items in the array are undefined, resulting in an empty array. However, I can see where the confusion might be coming from.

array[10] = 10

This line does not set the length of the array; it sets a specific item to the value of 10. So after this line, your array will have 4 elements: 1, 2, 3, and... 10.

In an array, you can specify the index for a particular value. If you omit it, the next index will simply increment by 1. Try this:

var array = [1, 2, 3];
array[10] = 10;

array.forEach((value, index) => console.log(value, index));

If you run this code on JSFiddle: https://jsfiddle.net/eetmkd95/1/, you will see the output displayed as:

1 0 
2 1 
3 2 
10 10

Why? Because when you don't specify the index, it increments based on +1, and if you do specify the index, it places the value at that index. Remember, you are specifying the INDEX, not the length of the array.

Now try this piece of code:

var array = [1, 2, 3];
array.length = 10;
array[8] = 10;

array.forEach((value, ix) => console.log(value, ix));
console.log(array.length);

You may notice that even though the length property reports 10, forEach only prints 4 lines. This happens because forEach only displays items with number indexes that actually exist in the array. Also, it's worth noting that the reliability of the length property can vary based on whether you set it to a lower or higher value.

To further understand this concept, consider reading "You Don't Know JS" by Kyle Simpson, specifically the "Array(..)" section on page 44 in the "Types & Grammar" book. Additionally, you may find this resource helpful:

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

What is the best way to replicate the Ctrl+A action on an element using jQuery or JavaScript?

Is there a way to trigger the Ctrl+A key combination in a textarea element when a specific event occurs, without resorting to caret positioning or selecting all text separately? I'm looking for a method that simulates hitting Ctrl+A using a cross-brow ...

What are the distinctions between altering the value of a textarea with JS and user input?

I've come across an interesting scenario that I'm hoping someone with more expertise in JavaScript can help me with. There is a popular online forum site that I frequently use. In the past, I was able to easily update a comment textarea using Jav ...

How can I substitute specific words in a string with multiple words from an array?

I'm faced with a challenge where I need to replace asterisks (*) in a sentence with words from an array. Let's take an example: let sentence = 'My * is * years old.'; let words = ['dog', 3]; //expected result => My dog is ...

Accessing store state in axios plugin with Nuxt.js

I've encountered a problem where I have a token stored, but I'm struggling to access it in my axios plugin while using Nuxt.js. In the past with just Vue, it was simple to import the store and access the token. However, I'm having difficulty ...

Tips for fixing footer accordion overlap issues

Just starting out with jQuery and using the Accordion feature. Noticed that when I click on the accordion, it overlaps with the footer. How can I prevent this from happening? Here is the code for the footer - <footer> <div class="row footer_ ...

Troubleshooting issues with NodeJS and Express authentication middleware functionality

I am currently working on implementing the isUserAuthenticated function to run on every server request. This function is required in the app.js file and utilized using app.use(authenticate.isUserAuthenticated). In my project, there is an /authenticate rou ...

Sharing parameters between functions in JavaScript

I have a working code but I want to modify the function getLocation to accept 2 arguments that will be passed to getDistanceFromLatLonInKm within the ajmo function. Currently, getDistanceFromLatLonInKm has hardcoded arguments and I would like to use variab ...

Ordering and displaying data with AngularJS

Trying to maintain a constant gap of 5 between pagination elements, regardless of the total length. For instance, with $scope.itemsPerPage = 5 and total object length of 20, we should have 4 pages in pagination. However, if $scope.itemsPerPage = 2 and tota ...

What can be done to stop the Datepicker from exiting the Dialog box and causing it to malfunction?

While creating a form inside a dialog box, I encountered an issue with the date picker functionality. Whenever I try to select a date, it disappears and breaks, rendering the last days of the calendar inaccessible. You can view an example of this problem i ...

Ensuring Node.js backend JavaScript waits for completion of my bash script before proceeding

Running three bash commands through a Node.js code snippet. Here's a portion of the script: exec(str, function(error, stdout, stderr){ console.log('stdout:'+stdout); console.log('stderr:'+stderr); if(error!=null){ ...

Saving a multi-dimensional array in a JSONArray on Android devices

I am currently working with a multidimensional array that has two columns (the number of columns is fixed but the number of rows can vary). I understand how to store a single dimensional array in a JSONArray, but I am struggling to grasp how to store a m ...

Employ jquery to exclusively add either a beginning tag or closing tag

As I continue to learn, I have discovered that using replaceWith('<section>') or after('<section>') results in the full element being inserted in both scenarios: <section></section> Interestingly, when at ...

Including item from ajax not within $.when function finished

function fetchData(){ return $.ajax({ url : 'URL1', data : { id : id }, type : 'GET', }); } function fetchItemData(item_id) { return $.ajax({ url: 'URL2', data: { item_id: it ...

When utilizing String: Any, my JSON array appears to be devoid of any data

Whenever I try to use double scopes like [[String: Any]], my jsonArray ends up empty. How can I get it to work properly? I attempted to use [String: Any] and it worked, but now I can't access [0]["aaData"] (for example) as it gives me the error "Cann ...

Utilizing JavaScript to capture a client's timestamp and subsequently learning how to analyze and compare different time values

Similar Question: How to implement a timeout for detecting user typing delays I am developing a feature to track user typing activity. My goal is to record the time whenever a user types and then set a timeout that triggers after 3 seconds to check fo ...

How is it possible to establish dual MySQL connections to separate databases within a single Sails js model?

In my Employee.js and EmployeeController.js files, I have set up two connections as follows: module.exports = { connection: 'LocalhostMysqlServer', attributes: { name:{ type:"string", required:true, ...

Text displaying as actionable icons

In my React project, I am utilizing material-table (https://material-table.com/#/) and have successfully imported the necessary icons. However, when viewing the action bar, the icons are displaying as plain text instead of the Material Icon. import React, ...

Steps to Execute PHP Mail Form Script After Successful Form Submission

My HTML Form with PHP is causing an issue where the Mail() script runs automatically, sending me empty emails whenever someone visits the website. I need it to only run when the form is successfully submitted. Can you assist? <!--HTML FORM--><for ...

Troubleshooting a Node.js / Express / JavaScript scope dilemma

I've been developing a Node.js web application using handlebars and express for templating and routing. However, I've encountered an issue within the app.get('/', function(){ ... }) block. The error message that appears when it runs is ...

Could you provide suggestions on how to update the content of an HTML tag within a Vue component?

I am new to Vue.js and struggling to grasp its concepts. I am interested in finding a way for my custom Vue component (UnorderedList) to manipulate the content within it. For example, if I have <p> tags inside my component like this : <UnorderedL ...