Execute a personalized function when an array is updated or created in JavaScript

I have experience in adding custom properties to objects.

For example, if I have a method called foo,

const foo = () => { console.log('custom method'); }

I can add the foo method to the Array prototype and use it with array variables by

Array.prototype.foo = foo;

Then, by creating an array named,

bar = [1, 2, 3];

and calling

bar.foo()

My custom foo method will be executed. However, I am unsure how to automatically run the foo method every time a new array is created or updated.

I am looking to run a custom method and store data during array creation/update in JavaScript. How can this be achieved?

Imagine I have a custom method,

const customMethod = () => {
   ...performing some operations    
}

I want this custom method to run every time a new array is created, storing additional data such as the maximum value within the array. This way, I can access the maximum value by calling myArray.maximum without having to recalculate it each time.

A similar approach accomplishes this by adding an event listener and a new push method to trigger an event whenever an item is added to the array using the custom push method. However, the custom function will not be triggered if the regular Array.prototype.push method is used or when creating a new array using the spread operator like newArr = [...oldArray, value].

Update: Further research and the links provided in the comments reveal that directly modifying the Array object without extending it or creating a custom array type from scratch (which is not ideal) is not feasible.

I attempted to extend the existing Array type to create MyCustomArray, but it did not behave as expected.

class MyCustomArray extends Array {
   constructor(...args) {
      super(...args);
      console.log('custom array');
   }
}

Is there a way to extend the Array to create a CustomArray type and add a listener so that each time I create/update a CustomArray, it automatically calculates the maximum value and sets it as an array property (with minimal code changes)?

Therefore, my CustomArray would retain all typical array methods and properties but also calculate and store the maximum value each time it is updated/created.

Answer №1

Attempting to "hijack" all arrays in such a manner may not be possible. Even if you attempt to alter the native Array function, arrays created using the literal notation, such as [], will remain unaffected:

console.log(new Array(1,2,3));
console.log([4,5,6]);

Array = function () {
  throw new Error;
};

try {
  console.log(new Array(1,2,3));
} catch (e) {
  console.log('Unable to create array with new Array');
}

console.log([4,5,6]);

It is necessary to pass your arrays to a different solution. One possible approach is using a proxy:

const spy =
  (arr, fn) =>
    new Proxy(arr, {
      get(target, prop) {
        if (prop === "max") {
          return Math.max(...target);
        }
        if (prop === "min") {
          return Math.min(...target);
        }
        if (typeof target[prop] === "function") {
          fn();
        }
        return target[prop];
      }
    });


const arr = spy([1,2,3], () => console.log('spied'));
arr.push(500);
arr.push(-10);

console.log(arr.min, arr.max, JSON.stringify(arr), Array.isArray(arr));

A benefit of using a proxy is that it can be implemented without causing disruptions. In the provided example, arr remains an array with standard functionality. Despite the proxy, operations like Array.isArray and JSON.stringify still behave as expected.

It should be noted that with the current implementation, any subsequent arrays created from arr will not be automatically proxied:

const arr = spy([1,2,3], fn);
arr.slice(1); // [2,3] (non-proxied array!)

Answer №2

While it may seem a bit forceful, the Array in JavaScript has a unique feature where you can specify a constructor for an extension class. When a constructor is provided, the methods that create new arrays will utilize that constructor. For example, if you use myCustomArray.filter, it will produce a result of type myCustomArray instead of the usual Array object. However, if a constructor is not provided, this functionality will not work.

If you want easy access to a specific custom feature of an Array in a custom type, you could set the value to null upon creation. Then, you can extend methods like pop to also null the value and create a method that retrieves either the cached value or calculates, caches, and returns the current value.

There are only a few array methods that modify the existing array instead of creating a new one, so implementing this approach should not be too difficult.

Answer №3

You're on the right track with your approach:

class MyCustomArray extends Array {
   constructor(...args) {
      super(...args);
      console.log('custom array');
   }
}

To improve your code, you just need to modify the class you are extending from. It should be Array<T> instead of just Array like this:

class MyCustomArray extends Array<T> {
   constructor(...items) {
      super(...items);
      console.log('custom array');
   }
}

In this case, <T> represents the type of objects stored in the array. For example, if it's a number array, you would use <number>.

Now you can add custom functionalities to this array and create instances using the following syntax:

const array = new MyCustomArray(item1, item2...)

I hope this explanation is helpful for you

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

Modifying iframe src using click event from a separate component in Angular 10

I am looking to dynamically update the src attribute of an iframe when the menu bar is clicked. The menu bar resides in a separate component and includes a dropdown menu for changing languages. Depending on which language is selected, I want to update the ...

Image caption dynamically updated to match thumbnail caption using jQuery upon click event

My goal is to dynamically load the data-caption of thumbnail images when clicked, and then update the main image's data-caption when the main image is changed with a thumb image. I am currently struggling to make the data-caption update along with the ...

the sequence in which a node executes a javascript function

Trying to update req.session.cart with new values for prod.quantity and prod.qtyCount in the shoppingCart field of order.save(). The issue is that orders are being saved with default quantity and qtyCount values, even though I'm setting cartProducts[ ...

Submitting a JavaScript array to MongoDB using a React application: A guide to success!

As a beginner delving into the world of React and MongoDB, I'm encountering difficulties in establishing communication between the two technologies. Recently, I've been following a detailed tutorial on Medium that focuses on utilizing the Plaid A ...

Using CSS to position elements absolutely while also adjusting the width of the div

In one section of my website, I have a specific div structure. This structure consists of two divs stacked on top of each other. The first div is divided into two parts: one part with a width of 63% and another part with a button. Beneath the first div, t ...

Unable to display and conceal div elements

<ol class="novice"> <li> <p class="glava">HTML</p> <div class="vsebina"> <p>Hyper Text Markup Language (slovensko jezik za označevanje nadbesedila...</p> </div> </li> <li> ...

Getting rid of the Horizontal Scroll Bar

Having trouble with a persistent horizontal scrollbar in the "section3__container" container despite attempts to adjust size and overflow settings. Need assistance in removing this unwanted feature. <html lang="en"> <head> <m ...

Guide on Updating the ColModel Dynamically in JAVASCRIPT/HTML using clearGridData, setGridParam, and reloadGrid Functions

I am trying to figure out how to dynamically change the colmodel of my grid using a function that is called by a SELECT. The reason for this is because my grid has different periods and needs to display either cost or tons based on user selection. Below i ...

What is the best way to display HTML content inside a pop-over window?

How can I load popover content from another HTML file using templateUrl in AngularJS? Check out the demo below: HTML: <!DOCTYPE html> <html ng-app="plunker"> <head> <meta charset="utf-8"/> <title>AngularJS Plunker& ...

Protect your website's ajax-generated content from being indexed by search engines with these strategies

Recently, Google made an update allowing its crawler to index ajax-generated content on web pages by following specific guidelines. However, my requirement is to ensure that no search engine can crawl my ajax-generated content. So, my question is: What ...

What is the method for attaching a keypress event to an HTML document?

Looking to add an interactive touch to my website by creating a "press any key" page. When a key is pressed, I want it to kick off animations that bring the page to life - like sliding elements in from different directions. Open to using jQuery or plain ...

Newbie Inquiry Renewed: What is the best way to convert this into a functional hyperlink that maintains the data received from the ID tag?

I have no prior training etc. If you are not willing to help, please refrain from responding as I am simply trying to learn here. <a id="player-web-Link">View in Depth Stats</a> This code snippet loads the following image: https://i.stack.i ...

Deleting an element in an Array of objects using Typescript

export class AppComponent implements OnInit { title = 'bucketList'; bucketList: BucketListItem[] = [ new BucketListItem( "Goa Trip", "Travel to Goa" ) ]; ngOnInit() { } onItemAdded(eventData) ...

The supertest request body cannot be found

Testing my express server POST endpoint using supertest has been a challenge for me. Although everything works perfectly in postman, I encountered an issue when trying to pass body parameters into the test. It seems like the body parameters are not being p ...

Easily generate a component directory complete with all essential files in just a few simple clicks

In my work with React and the typical app structure, I utilize a directory called src/components to store all of my React components. I am looking for a way to streamline the process of creating new components. I would like to be able to generate a compon ...

Issue with PHP retrieving initial value of post data

Hi there, I am facing an issue with my PHP code where the first value of the input field is not being displayed. However, when I check the console.log, it shows correctly. Here is my console.log output: https://i.sstatic.net/eZvg6.png PHP Output: https ...

When working with the Google Sheets API, an error occurred: "this.http.put(...).map is not a valid

Having difficulty with a straightforward request to the Google Sheets API using the PUT method. I followed the syntax for http.put, but an error keeps popping up: this.http.put(...).map is not a function. Here's my code snippet: return this.http ...

Tips for validating a text input field depending on the selected value in a dropdown menu using AngularJS

When a user selects from the dropdown menu, they can choose between Number and Decimalnumber. If the user selects Number, the text box should only allow whole numbers (e.g. 22, 33, 444, 345436). The user should not be able to enter decimal values like 22 ...

What is the most efficient method for executing over 1,000 queries on MongoDB using nodejs?

I have a task to run around 1,000 queries on MongoDB in order to check for matches on a specific object property. I must confess that my code is quite amateurish, but I am open to any suggestions on how to improve its efficiency. The current version works ...

"Enhance the visualization of your data with Apexcharts by accurately coloring the columns

When attempting to color the graphic using an array, only one color is applied to all three columns, despite declaring a different color for each column. options: { chart: { type: 'bar', id: 'chart', }, colors: ['#3 ...