In what way does the map assign the new value in this scenario?

I have an array named this.list and the goal is to iterate over its items and assign new values to them:

this.list = this.list.map(item => {
  if (item.id === target.id) {
    item.dataX = parseFloat(target.getAttribute('data-x'))
    item.dataY = parseFloat(target.getAttribute('data-y'))
  }
  return item
})

Surprisingly, I noticed that the following code also worked:

this.list.map(item => {
  if (item.id === target.id) {
    item.dataX = parseFloat(target.getAttribute('data-x'))
    item.dataY = parseFloat(target.getAttribute('data-y'))
  }
  return item
}) 

I'm puzzled as to why this.json is getting a new value from map even though there is no explicit assignment happening.

Answer №1

After reviewing the provided example, here are some comments for clarification:

// The function map creates a _new_ array
// with all existing elements.
// This new array is then assigned back to the original variable,
// effectively replacing the original array.
this.list = this.list.map(item => {

  // When referencing "item" here, it directly corresponds to the object element within
  // the current list. Any changes made to this object will affect the original item in the list.
  if (item.id === target.id) {

    // These lines represent your assignments.
    item.dataX = parseFloat(target.getAttribute('data-x'));
    item.dataY = parseFloat(target.getAttribute('data-y'));
  }

  // Despite returning the item which would replace the
  // existing element in the new list, the returned item itself
  // remains as the actual element already present in the list.
  return item;
});

So, in terms of outcome, the following code provides an equivalent functionality since you are updating the initial values within the original variable:

this.list.forEach(item => {
  if (item.id === target.id) {
    item.dataX = parseFloat(target.getAttribute('data-x'));
    item.dataY = parseFloat(target.getAttribute('data-y'));
  }
});

If you wish to perform this without mutating the original objects, you can consider the following approach:

var result = this.list.map(item => {
  return target.id === item.id ? {
    id: item.id,
    dataX: parseFloat(target.getAttribute('data-x')),
    dataY: parseFloat(target.getAttribute('data-y'))
  } : item;
});

In instances where 'item' carries additional data that needs to be preserved, you might need to clone the object. One methodology could be modeling the types accordingly, like shown below:

class Item {
  constructor(id, x, y) {
    this.id = id;
    this.dataX = dataX;
    this.dataY = dataY;
  }

  // Immutability style setter, returns the result
  // as a new instance.
  withData(dataX, dataY) {
    return new Item(this.id, dataX, dataY);
  }
}

var result = this.list.map(item => {
  return item.id === target.id ? item.withData(
    parseFloat(target.getAttribute('data-x')),
    parseFloat(target.getAttribute('data-y'))
  ) : item;
});

In the above scenario, this.list contains the untouched original array with all its elements prior to the mapping operation.

result consists of both 'updated' elements (new instances of elements that match target.id) and original items that do not.

Tracking Instances...

To illustrate this further, suppose we number all instances before the map operation using 'map' and assign it back to 'this.list':

this.list
  Array 1
  - Item 1
  - Item 2
  - Item 3
  - Item 4

Post-map operation, while the instances have been updated but remain the same, the array itself is now a different instance:

this.list -> map -> this.list
  Array 1             Array 2 (NEW)
  - Item 1       ->   - Item 1
  - Item 2       ->   - Item 2
  - Item 3       ->   - Item 3
  - Item 4       ->   - Item 4

In comparison to the forEach example, no change occurs because the instances are updated in place:

this.list (forEach) this.list (No change)
  Array 1             Array 1
  - Item 1            - Item 1
  - Item 2            - Item 2
  - Item 3            - Item 3
  - Item 4            - Item 4

In each of the immutable examples, though this.list retains its original form, 'result' becomes a distinct array instance with matched items being altered. Here, 'Item 1' was matched and updated:

this.list -> map -> result             this.list (Untouched)
  Array 1             Array 2 (NEW)      Array 1
  - Item 1            - Item 5 (NEW)     - Item 1
  - Item 2       ->   - Item 2           - Item 2
  - Item 3       ->   - Item 3           - Item 3
  - Item 4       ->   - Item 4           - Item 4

Answer №2

Regarding the documentation for the map function:

The map function does not change the original array it is called on (although the callback function, if used, might).

Keep in mind that the item variable you are working with in the callback function is a reference to the real this.list element and in this situation, you are altering the item object.

Answer №3

When working with JavaScript, it's important to remember that objects are stored as references. This means that when you iterate over an array and make changes to the objects within it, you are actually modifying the original object. The code snippet below illustrates this concept:

let original = [{x: 5}];
let copied = original;
copied[0].x = 6;
console.log(original[0].x); // 6

To avoid altering the original object, you will need to either recreate the object or clone it in some way.

this.list = this.list.map(item => {
    if (item.id === target.id) {
      item = {
        id: target.id,
        dataX: parseFloat(target.getAttribute('data-x')),
        dataY: parseFloat(target.getAttribute('data-y')),
        ...
      };
    }
    return item
})

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

Add a new row to the table when a dropdown option is selected, and remove the row when deleted. Ensure that the row is only added

Here is my specific requirement: I need a table with a default row containing a dropdown menu in the first column. When an option is selected from the dropdown, a new table row should be added with the same content as the main row and a delete button for ...

AngularJS: How do I stop the $interval from running indefinitely?

After spending hours reading the documentation, it's now 3am and I'm at my wit's end. Below is my controller code: controller('makeDashCtrl', function ($scope, $rootScope, $cookies, $location, $http, $interval) { var userId ...

Challenges with resizing images in SVG using D3

I have an SVG image created using d3. I am facing an issue where the svg is extending beyond its parent div container. Here is the code snippet: <div id="test" style="{width: 500px; height:500px;}"> <svg></svg> </div> ...

Refreshing a div using ajax technology

I am attempting to use Ajax to update an h3 element with the id data. The Ajax call is making a get request to fetch data from an API, but for some reason, the HTML content is not getting updated. This is how the JSON data looks: {ticker: "TEST", Price: 7 ...

The repairDatabase function cannot be found in the Collection.rawDatabase() method

Seeking guidance on repairing a database within Meteor. Currently executing the following code: Meteor.methods({ 'repairDB'(){ Users.rawDatabase().repairDatabase(); return true; } }); Encountering the following error: I20170630-18: ...

Using socket.io in a Django template without the need for the node.js service or socket.io.js file

I am working on a Django app that requires real-time push to clients. I have decided to use node.js and socket.io as it is considered the easiest platform for achieving this functionality. To implement this, I have included the socket.io framework code in ...

What could be causing the error in sending JSON data from JavaScript to Flask?

Check out this cool javascript code snippet I wrote: <script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> <script type=text/javascript> $(function() { $.ajax({ type: 'PO ...

Is it necessary for JavaScript functions to be stored in a separate file in order to be invoked?

Here is the scenario that unfolded: Within a .php file, I had the following form: <form action="/flash_card/scripts/create_user_gate.php" onsubmit="return validateForm()" method="post"> <table align="center"> ...

How to successfully send data props from child components to parent in Vue3

I am currently working on a personal project to add to my portfolio. The project involves creating a registration site where users can input their personal data, shipping information, and then review everything before submission. To streamline the process ...

The setState function in React is not being updated within the callback function

I've encountered an issue while working on a project in React. The puzzling part is why the variable selectedRow remains null even after using the setSelectedRow function inside the onClick callback. Despite my efforts to log it, the value always retu ...

How to toggle visibility of a Bootstrap modal using VueJS (using CDN) without displaying the overlay

I have integrated VueJS into a single page using the CDN, which prevents me from utilizing bootstrap-vue. The functionality to display and hide a modal based on the value of the showModal data is currently working. However, the gray overlay surrounding th ...

Trouble with ng-repeat when working with nested json data

Check out this app demo: http://jsfiddle.net/TR4WC/2/ I feel like I might be overlooking something. I had to loop twice to access the 2nd array. <li ng-repeat="order in orders"> <span ng-repeat="sales in order.sales> {{sales.sales ...

Discovering identical elements within a list in Python through index-based location scanning

Check out this JavaScript code that can determine whether there are any duplicate elements in an array. function findDuplicates(arr) { let seen = []; for (let i = 0; i < arr.length; i++) { if(seen[arr[i]] === 1) { ...

Launch a YouTube video within a sleek and stylish Bootstrap modal popup

I am currently extracting video data from my SQL table. The fields in the table are as follows: - sidebar_video_id (auto increment) - sidebar_video_nev - sidebar_video_link (full URL) - sidebar_video_v_id (video ID at the end of the URL) What I'm tr ...

Guide on displaying the name attribute of a button along with its price in a separate div when clicked

Upon clicking the Koala button, I want to display a message showing the id name of the button and the corresponding price for Koalas. Here is the HTML code snippet: <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <link h ...

Tips for sending a URL in form-data as a file with JavaScript or Axios

Currently, I am using Vue.js and Axios to send form data to a specific link. However, I encountered an issue where the file is not being sent and I am receiving an error message. The parameter 'file' had the following problems: file transferred w ...

Two separate ajax functions executed sequentially both yield identical results

I am encountering a strange issue with 2 different ajax functions being called consecutively. Each function fetches a different value and populates different text boxes, but they both return the value of the first function called. Here is the code snippet ...

ReactAppI am facing an issue where the browser fails to refresh the page upon saving changes in my JavaScript file using the VS code editor

Can anyone remind me of the tool we can install to refresh the browser page automatically whenever we save changes in our editor? ...

What is the best way to save a JSON stream to a file in Node.js?

I am facing an issue with writing a complete JSON object to a file as it is received. Currently, I am using const file = fs.createWriteStream('./example.file'); var inputStream = JSON.parse(generatedData); fs.write(inputStream+"\n"); The d ...

Iterating through the startPrivateConversation method in Botkit for a multitude of users

In order to send an update to all my users, I created a new bot controller in a separate js file. To achieve this successfully, I needed to implement a notification function inside the controller's rtm_open function. The goal was to iterate through th ...