What is the best way to loop through an array in JavaScript, calling a prototype function recursively within itself?

I am currently working on developing a custom polyfill for the Array.flat() method. However, I have encountered some challenges when trying to call the function recursively within itself to flatten nested arrays further. It seems that when I write code without using prototypes, the flattening works correctly. But once I attempt to create a prototype function, I cannot achieve the desired flattened array. I suspect that the issue lies with the 'this' keyword. Please review my code below.

Below is the code snippet:

let arrayFlat = [1, 2, 3, [4, 5, 6, [7, 8, [9]], 10, [11, 12]], [13, [14, 15]]];

const flatArray = (array) => {
  let output = [];
  const flatten = (array) => {
    for (let i = 0; i < array.length; i++) {
      if (Array.isArray(array[i])) {
        flatten(array[i]);
      } else {
        output.push(array[i]);
      }
    }
    return output;
  };
  return flatten(array);
};

Array.prototype.myFlat = function () {
  let output = [];
  for (let i = 0; i < this.length; i++) {
    if (Array.isArray(this[i])) {
      console.log(this[i]);
      this[i].myFlat();
    } else {
      output.push(this[i]);
    }
  }
  return output;
};

Answer №1

Your initial code snippet creates a single 'output' array. As you recursively call the 'flatten' function, it continuously appends to this same 'output' array which is within the closure of the 'flatten' function. Once all recursion is complete, the final array is returned.

In the second code example, a new array is created with each recursive call. Each recursion generates a new array, flattens it, and returns the result. However, since the return values are not stored or used, these arrays are essentially discarded.

You do have a few options:

  1. Make your code similar to the first example by using an internal function for recursion and a shared closure variable:
Array.prototype.myFlat = function () {
  let output = [];
  const flatten = (array) => {
    for (let i = 0; i < array.length; i++) {
      if (Array.isArray(array[i])) {
        flatten(array[i]);
      } else {
        output.push(array[i]);
      }
    }
    return output;
  };
  return flatten(this);
}
  1. Pass the output array as a parameter during recursion:
//                                 VVVVVV--- added parameter
Array.prototype.myFlat = function (output = []) {
  for (let i = 0; i < this.length; i++) {
    if (Array.isArray(this[i])) {
      this[i].myFlat(output); // <---- pass along the array
    } else {
      output.push(this[i]);
    }
  }
  return output;
};
  1. Maintain separate arrays but combine them as the stack unwinds:
Array.prototype.myFlat = function () {
  let output = [];
  for (let i = 0; i < this.length; i++) {
    if (Array.isArray(this[i])) {
      output.push(...this[i].myFlat()); // <---- merging arrays
    } else {
      output.push(this[i]);
    }
  }
  return output;
};

Answer №2

One of my core beliefs is to strive for lean and concise classes, opting for functional interfaces whenever feasible -

function myFlatten(arr) {
  return Array.isArray(arr)
    ? arr.reduce((result, value) => result.concat(myFlatten(value)), [])
    : [arr]
}

Array.prototype.myFlatten = function() { return myFlatten(this) }

console.log([1,[2,[3],4],[[5]],6,[[[7]]]].myFlatten())
// [ 1, 2, 3, 4, 5, 6, 7 ]

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

"Can someone guide me on where to place the JavaScript code within this Bootstrap snippet when working with CakePHP

I'm currently delving into CakePHP and am eager to incorporate this Bootstrap code snippet from onto my website. I've successfully added the HTML to the .ctp file in the Pages directory and styled it with custom.less, but I hit a roadblock when ...

angularjs and cakephp working together to handle a request

I've implemented a method in the UsersController to add new users to the database. In the cakephp ctp views, everything seems fine as the request isn't being black-holed and I'm using 'post' for this purpose. However, when I transi ...

Retrieve documents from MongoDB database that have specific characteristics

Hello everyone, Today I'm trying to navigate mongoose queries. Imagine we have a collection like this: [ {letter: "A", name: "Books", action: "read"}, {letter: "B", name: "Notebook", action: &q ...

error when trying to bind attributes to knockout components

I am trying to dynamically add an id attribute to a tag, but it keeps giving me an error. "Uncaught ReferenceError: Unable to process binding "attr: function (){return {id:id} }" Message: id is not defined" Here is my HTML code- <label data-bind= ...

What is the most effective method for determining the distance between two UK Postcodes?

Can you suggest a reliable method for calculating the distance between two UK postcodes in order to determine if they are within range? I do not intend to display a map, but instead provide a list of results for valid locations. For example, showing loca ...

Tips on effectively rendering child components conditionally in React

My components currently consist of an AddBookPanel containing the AddBookForm. I am looking to implement a feature where the form is displayed upon clicking the 'AddBookButton', and hidden when the 'x' button (image within AddBookForm c ...

Implementing AngularJS to display different divs according to the selected value

I am attempting to utilize the value of an HTML select element to toggle the visibility of specific div tags using AngularJS. Below is the code snippet I have been working with: <body ng-app="kiosk" id="ng-app" > <div class="page" ng-controll ...

What is the method for determining the proportional color that falls between the three provided colors using a specified percentage?

After receiving three hexadecimal colors from the user, such as: #39bf26 #c7c228 #C7282E The user then needs to select a percentage between 1 and 100. If the percentage is 100, the color returned will be the first color entered: #39bf26. If the percen ...

Switching styles in AngularJS without using ng-class

My goal is to allow users to switch the class from incomplete to complete when they click a button and the function(response) returns 1. I have attempted to use ng-class, but it is not effective because the HTML elements are generated with a PHP loop. This ...

Discover the route of a string within an object or array

Given a specific object or array structure, I am looking to verify the existence of a certain path within it. Example 1: const path = "data/message"; const info = { data: { school: 'yaba', age: 'tolu', message: 'true ...

Stop the print dialog box from appearing when using the Ctrl + P shortcut

I'm working on an Angular app and I want to prevent the print dialog from opening when pressing "Ctrl + P". To address this issue, I have implemented the following code: window.onbeforeprint = (event) => { event.stopPropagation(); cons ...

Run a JavaScript function on a webpage loaded through an AJAX response

I need to trigger a function through an AJAX request sent from the server. The function itself is not located on the calling page. Here's an example of what I am trying to achieve: 1. PHP script being called: <script> function execute() { ...

A guide on generating multiple arrays within Laravel 5

Looking to create multiple arrays using PHP (specifically Laravel 5)? Here are two arrays to work with: $tags=['en' =>[]]; $TAGS = ['test1','test2','test3',...] The goal is to return a specific array structure l ...

From SketchUp to Canvas

I've been trying to figure out how to display a 3D model created in SketchUp on a web page. After discovering three.js and exporting the model to a .dae file for use with ColladaLoader, I still can't get it to appear on my canvas. (I'm using ...

The outer DIV will envelop and grow taller in conjunction with the inner DIV

Could use a little help here. Thank you :) I'm having trouble figuring out how to get the outer div to wrap around the inner div and expand upwards with the content inside the inner editable div. The inner div should expand from bottom to top, and t ...

The focus on the input text in AngularJS functions properly on desktop devices but not on iPads

I am facing an issue with the search input box in my application. Even though the search input opens when I click a button, it is not autofocusing. Here is the snippet of my code: $scope.goSearch = function () { $scope.$broadcast("focusTextInput"); } ...

Getting a subset of attributes from an object in Typescript: A step-by-step guide

For instance: type T = { prop1: boolean; prop2: number; prop3: string; }; const obj1 = { prop1: true, prop2: 1, prop3: 'hello', prop4: false, prop5: 'world' } const obj2: T = obj1 as T; // the outcome is not as antic ...

Using ngFor results in duplicate instances of ng-template

I'm facing a challenge with the ngFor directive and I'm struggling to find a solution: <ng-container *ngIf="user.images.length > 0"> <div *ngFor="let image of images"> <img *ngIf="i ...

Convert require imports to Node.js using the import statement

Currently learning NodeJs and encountering a problem while searching for solutions. It seems like what I am looking for is either too basic or not much of an issue. I am working on integrating nodejs with angular2, which involves lines of code like: impo ...

The functionality of changing the checkbox to "checked" by clicking on the span is not

How can I create a toggle button with a checkbox using css and jquery? Clicking on the span representing the toggle button should change the checked property of the checkbox. Currently, the span does not change the property, even though it triggers the c ...