Как изменить массив объектов js

The code below comes from jQuery UI Autocomplete: var projects = [ { value: "jquery", label: "jQuery", desc: "the write less, do more, JavaScript library", icon: "

The code below comes from jQuery UI Autocomplete:

var projects = [
    {
        value: "jquery",
        label: "jQuery",
        desc: "the write less, do more, JavaScript library",
        icon: "jquery_32x32.png"
    },
    {
        value: "jquery-ui",
        label: "jQuery UI",
        desc: "the official user interface library for jQuery",
        icon: "jqueryui_32x32.png"
    },
    {
        value: "sizzlejs",
        label: "Sizzle JS",
        desc: "a pure-JavaScript CSS selector engine",
        icon: "sizzlejs_32x32.png"
    }
];

For example, I want to change the desc value of jquery-ui. How can I do that?

Additionally, is there a faster way to get the data? I mean give the object a name to fetch its data, just like the object inside an array? So it would be something like jquery-ui.jquery-ui.desc = ....

imjared's user avatar

imjared

18.6k3 gold badges48 silver badges71 bronze badges

asked Jan 14, 2011 at 9:59

qinHaiXiang's user avatar

qinHaiXiangqinHaiXiang

5,83112 gold badges46 silver badges60 bronze badges

4

It is quite simple

  • Find the index of the object using findIndex method.
  • Store the index in variable.
  • Do a simple update like this: yourArray[indexThatyouFind]
//Initailize array of objects.
let myArray = [
  {id: 0, name: "Jhon"},
  {id: 1, name: "Sara"},
  {id: 2, name: "Domnic"},
  {id: 3, name: "Bravo"}
],
    
//Find index of specific object using findIndex method.    
objIndex = myArray.findIndex((obj => obj.id == 1));

//Log object to Console.
console.log("Before update: ", myArray[objIndex])

//Update object's name property.
myArray[objIndex].name = "Laila"

//Log object to console again.
console.log("After update: ", myArray[objIndex])

Vega's user avatar

Vega

27.1k27 gold badges91 silver badges98 bronze badges

answered Jan 30, 2017 at 14:43

Umair Ahmed's user avatar

9

You have to search in the array like:

function changeDesc( value, desc ) {
   for (var i in projects) {
     if (projects[i].value == value) {
        projects[i].desc = desc;
        break; //Stop this loop, we found it!
     }
   }
}

and use it like

var projects = [ ... ];
changeDesc ( 'jquery-ui', 'new description' );

UPDATE:

To get it faster:

var projects = {
   jqueryUi : {
      value:  'lol1',
      desc:   'lol2'
   }
};

projects.jqueryUi.desc = 'new string';

(In according to Frédéric’s comment you shouldn’t use hyphen in the object key, or you should use «jquery-ui» and projects[«jquery-ui»] notation.)

answered Jan 14, 2011 at 10:05

Aston's user avatar

AstonAston

3,5821 gold badge20 silver badges18 bronze badges

4

The best solution, thanks to ES6.

This returns a new array with a replaced description for the object that contains a value equal to «jquery-ui».

const newProjects = projects.map(p =>
  p.value === 'jquery-ui'
    ? { ...p, desc: 'new description' }
    : p
);

Brett Hayes's user avatar

answered Aug 7, 2018 at 2:59

kintaro's user avatar

kintarokintaro

2,2832 gold badges16 silver badges16 bronze badges

6

Using map is the best solution without using extra libraries.(using ES6)

const state = [
{
    userId: 1,
    id: 100,
    title: "delectus aut autem",
    completed: false
},
{
    userId: 1,
    id: 101,
    title: "quis ut nam facilis et officia qui",
    completed: false
},
{
    userId: 1,
    id: 102,
    title: "fugiat veniam minus",
    completed: false
},
{
    userId: 1,
    id: 103,
    title: "et porro tempora",
    completed: true
}]

const newState = state.map(obj =>
    obj.id === "101" ? { ...obj, completed: true } : obj
);

OhhhThatVarun's user avatar

answered Sep 3, 2019 at 20:44

Ankit Kumar Rajpoot's user avatar

1

ES6 way, without mutating original data.

var projects = [
{
    value: "jquery",
    label: "jQuery",
    desc: "the write less, do more, JavaScript library",
    icon: "jquery_32x32.png"
},
{
    value: "jquery-ui",
    label: "jQuery UI",
    desc: "the official user interface library for jQuery",
    icon: "jqueryui_32x32.png"
}];

//find the index of object from array that you want to update
const objIndex = projects.findIndex(obj => obj.value === 'jquery-ui');

// Make sure to avoid incorrect replacement
// When specific item is not found
if (objIndex === -1) {
  return;
}

// make new object of updated object.   
const updatedObj = { ...projects[objIndex], desc: 'updated desc value'};

// make final new array of objects by combining updated object.
const updatedProjects = [
  ...projects.slice(0, objIndex),
  updatedObj,
  ...projects.slice(objIndex + 1),
];

console.log("original data=", projects);
console.log("updated data=", updatedProjects);

Konrad's user avatar

Konrad

17.9k4 gold badges29 silver badges58 bronze badges

answered May 24, 2018 at 8:03

Bimal Grg's user avatar

Bimal GrgBimal Grg

7,1422 gold badges24 silver badges21 bronze badges

0

You can use $.each() to iterate over the array and locate the object you’re interested in:

$.each(projects, function() {
    if (this.value == "jquery-ui") {
        this.desc = "Your new description";
    }
});

answered Jan 14, 2011 at 10:07

Frédéric Hamidi's user avatar

Frédéric HamidiFrédéric Hamidi

255k41 gold badges481 silver badges475 bronze badges

given the following data, we want to replace berries in the summerFruits list with watermelon.

const summerFruits = [
{id:1,name:'apple'}, 
{id:2, name:'orange'}, 
{id:3, name: 'berries'}];

const fruit = {id:3, name: 'watermelon'};

Two ways you can do this.

First approach:

//create a copy of summer fruits.
const summerFruitsCopy = [...summerFruits];

//find index of item to be replaced
const targetIndex = summerFruits.findIndex(f=>f.id===3); 

//replace the object with a new one.
summerFruitsCopy[targetIndex] = fruit;

Second approach: using map, and spread:

const summerFruitsCopy = summerFruits.map(fruitItem => 
fruitItem .id === fruit.id ? 
    {...summerFruits, ...fruit} : fruitItem );

summerFruitsCopy list will now return an array with updated object.

Fred's user avatar

Fred

8152 gold badges9 silver badges33 bronze badges

answered Oct 17, 2019 at 10:56

meol's user avatar

meolmeol

1,01111 silver badges7 bronze badges

1

you can use .find so in your example

   var projects = [
            {
                value: "jquery",
                label: "jQuery",
                desc: "the write less, do more, JavaScript library",
                icon: "jquery_32x32.png"
            },
            {
                value: "jquery-ui",
                label: "jQuery UI",
                desc: "the official user interface library for jQuery",
                icon: "jqueryui_32x32.png"
            },
            {
                value: "sizzlejs",
                label: "Sizzle JS",
                desc: "a pure-JavaScript CSS selector engine",
                icon: "sizzlejs_32x32.png"
            }
        ];

let project = projects.find((p) => {
    return p.value === 'jquery-ui';
});

project.desc = 'your value'

answered Jul 19, 2017 at 15:11

abe kur's user avatar

abe kurabe kur

2312 silver badges3 bronze badges

0

you need to know the index of the object you are changing. then its pretty simple

projects[1].desc= "new string";

answered Jan 14, 2011 at 10:04

elasticrash's user avatar

elasticrashelasticrash

1,1711 gold badge14 silver badges30 bronze badges

This is another answer involving find.
This relies on the fact that find:

  • iterates through every object in the array UNTIL a match is found
  • each object is provided to you and is MODIFIABLE

Here’s the critical Javascript snippet:

projects.find( function (p) {
    if (p.value !== 'jquery-ui') return false;
    p.desc = 'your value';
    return true;
} );

Here’s an alternate version of the same Javascript:

projects.find( function (p) {
    if (p.value === 'jquery-ui') {
        p.desc = 'your value';
        return true;
    }
    return false;
} );

Here’s an even shorter (and somewhat more evil version):

projects.find( p => p.value === 'jquery-ui' && ( p.desc = 'your value', true ) );

Here’s a full working version:

  let projects = [
            {
                value: "jquery",
                label: "jQuery",
                desc: "the write less, do more, JavaScript library",
                icon: "jquery_32x32.png"
            },
            {
                value: "jquery-ui",
                label: "jQuery UI",
                desc: "the official user interface library for jQuery",
                icon: "jqueryui_32x32.png"
            },
            {
                value: "sizzlejs",
                label: "Sizzle JS",
                desc: "a pure-JavaScript CSS selector engine",
                icon: "sizzlejs_32x32.png"
            }
        ];

projects.find( p => p.value === 'jquery-ui' && ( p.desc = 'your value', true ) );

console.log( JSON.stringify( projects, undefined, 2 ) );

answered May 4, 2020 at 6:51

Stephen Quan's user avatar

Stephen QuanStephen Quan

19.5k4 gold badges80 silver badges73 bronze badges

1

I think this way is better

const index = projects.findIndex(project => project.value==='jquery-ui');
projects[index].desc = "updated desc";

answered Feb 6, 2019 at 12:16

tsadkan yitbarek's user avatar

tsadkan yitbarektsadkan yitbarek

1,3302 gold badges11 silver badges26 bronze badges

1

const users = [
  { name: "Alex", age: 25 },
  { name: "John", age: 32 },
];

const newUsers = users.map((user) => ({
  ...user,
  age: user.age + 5, // just for example
}));

// newUsers = [
// {name:"Alex" , age:30},
// {name:"John , age:37}
// ]

answered Jun 24, 2021 at 16:17

Mohammadreza's user avatar

0

const state = [
{
    userId: 1,
    id: 100,
    title: "delectus aut autem",
    completed: false
},
{
    userId: 1,
    id: 101,
    title: "quis ut nam facilis et officia qui",
    completed: false
},
{
    userId: 1,
    id: 102,
    title: "fugiat veniam minus",
    completed: false
},
{
    userId: 1,
    id: 103,
    title: "et porro tempora",
    completed: true
}]

const newState = state.map(obj =>
    obj.id === "101" ? { ...obj, completed: true } : obj
);

answered Jul 9, 2022 at 7:20

Prachi Rajput's user avatar

1

Change value with conditions using for each loop

projects.forEach((p,index)=>{
    if(index === 1){
       p.value = "Updated jquery-ui"
    }
})

answered Sep 18, 2021 at 11:29

MD SHAYON's user avatar

// using higher-order functions to avoiding mutation
var projects = [
            {
                value: "jquery",
                label: "jQuery",
                desc: "the write less, do more, JavaScript library",
                icon: "jquery_32x32.png"
            },
            {
                value: "jquery-ui",
                label: "jQuery UI",
                desc: "the official user interface library for jQuery",
                icon: "jqueryui_32x32.png"
            },
            {
                value: "sizzlejs",
                label: "Sizzle JS",
                desc: "a pure-JavaScript CSS selector engine",
                icon: "sizzlejs_32x32.png"
            }
        ];

// using higher-order functions to avoiding mutation
index = projects.findIndex(x => x.value === 'jquery-ui');
[... projects.slice(0,index), {'x': 'xxxx'}, ...projects.slice(index + 1, projects.length)];

answered Sep 7, 2017 at 15:11

Leo Lanese's user avatar

Leo LaneseLeo Lanese

4604 silver badges5 bronze badges

2

try using forEach(item,index) helper

var projects = [
    {
        value: "jquery",
        label: "jQuery",
        desc: "the write less, do more, JavaScript library",
        icon: "jquery_32x32.png"
    },
    {
        value: "jquery-ui",
        label: "jQuery UI",
        desc: "the official user interface library for jQuery",
        icon: "jqueryui_32x32.png"
    },
    {
        value: "sizzlejs",
        label: "Sizzle JS",
        desc: "a pure-JavaScript CSS selector engine",
        icon: "sizzlejs_32x32.png"
    }
];

let search_to_change = 'jquery'

projects.forEach((item,index)=>{
   if(item.value == search_to_change )
      projects[index].desc = 'your description ' 
})

answered Jul 10, 2020 at 1:15

keroles Monsef's user avatar

let users = [
    {id: 1, name: 'Benedict'},
    {id: 2, name: 'Myles'},
    {id: 3, name: 'Happy'},
]

 users.map((user, index) => {
 if(user.id === 1){
  users[index] = {id: 1, name: 'Baba Benny'};    
 }
 
 return user
})


console.log(users)

What this code does is map over the object and then match the desired
with if statement,

if(user.id === 1) 

once there is match somewhere use its index to swap

 users[index] = {id: 1, name: 'Baba Benny'};

the object in the array and then return the modified array

answered Aug 17, 2021 at 11:04

mwangaben's user avatar

mwangabenmwangaben

8378 silver badges11 bronze badges

5

You can use map function —

const answers = this.state.answers.map(answer => {
  if(answer.id === id) return { id: id, value: e.target.value }
  return answer
})

this.setState({ answers: answers })

answered Jul 23, 2019 at 10:30

gandharv garg's user avatar

Here is a nice neat clear answer. I wasn’t 100% sure this would work but it seems to be fine. Please let me know if a lib is required for this, but I don’t think one is. Also if this doesn’t work in x browser please let me know. I tried this in Chrome IE11 and Edge they all seemed to work fine.

    var Students = [
        { ID: 1, FName: "Ajay", LName: "Test1", Age: 20},
        { ID: 2, FName: "Jack", LName: "Test2", Age: 21},
        { ID: 3, FName: "John", LName: "Test3", age: 22},
        { ID: 4, FName: "Steve", LName: "Test4", Age: 22}
    ]

    Students.forEach(function (Student) {
        if (Student.LName == 'Test1') {
            Student.LName = 'Smith'
        }
        if (Student.LName == 'Test2') {
            Student.LName = 'Black'
        }
    });

    Students.forEach(function (Student) {
        document.write(Student.FName + " " + Student.LName + "<BR>");
    });

Output should be as follows

Ajay Smith

Jack Black

John Test3

Steve Test4

answered Nov 10, 2020 at 22:49

Deathstalker's user avatar

Assuming you wanted to run a bit more complicated codes during the modification, you might reach for an if-else statement over the ternary operator approach

// original 'projects' array;
var projects = [
    {
        value: "jquery",
        label: "jQuery",
        desc: "the write less, do more, JavaScript library",
        icon: "jquery_32x32.png"
    },
    {
        value: "jquery-ui",
        label: "jQuery UI",
        desc: "the official user interface library for jQuery",
        icon: "jqueryui_32x32.png"
    },
    {
        value: "sizzlejs",
        label: "Sizzle JS",
        desc: "a pure-JavaScript CSS selector engine",
        icon: "sizzlejs_32x32.png"
    }
];
// modify original 'projects' array, and save modified array into 'projects' variable
projects = projects.map(project => {
// When there's an object where key 'value' has value 'jquery-ui'
    if (project.value == 'jquery-ui') {

// do stuff and set a new value for where object's key is 'value'
        project.value = 'updated value';

// do more stuff and also set a new value for where the object's key is 'label', etc.
        project.label = 'updated label';

// now return modified object
        return project;
    } else {
// just return object as is
        return project;
    }
});

// log modified 'projects' array
console.log(projects);

answered Feb 23, 2021 at 4:58

David_'s user avatar

We can also use Array’s map function to modify object of an array using Javascript.

function changeDesc(value, desc){
   projects.map((project) => project.value == value ? project.desc = desc : null)
}

changeDesc('jquery', 'new description')

answered Jul 27, 2017 at 4:43

Mahima Agrawal's user avatar

1

The power of javascript destructuring

const projects = [
  {
    value: 'jquery',
    label: 'jQuery',
    desc: 'the write less, do more, JavaScript library',
    icon: 'jquery_32x32.png',
    anotherObj: {
      value: 'jquery',
      label: 'jQuery',
      desc: 'the write less, do more, JavaScript library',
      icon: 'jquery_32x32.png',
    },
  },
  {
    value: 'jquery-ui',
    label: 'jQuery UI',
    desc: 'the official user interface library for jQuery',
    icon: 'jqueryui_32x32.png',
  },
  {
    value: 'sizzlejs',
    label: 'Sizzle JS',
    desc: 'a pure-JavaScript CSS selector engine',
    icon: 'sizzlejs_32x32.png',
  },
];

function createNewDate(date) {
  const newDate = [];
  date.map((obj, index) => {
    if (index === 0) {
      newDate.push({
        ...obj,
        value: 'Jquery??',
        label: 'Jquery is not that good',
        anotherObj: {
          ...obj.anotherObj,
          value: 'Javascript',
          label: 'Javascript',
          desc: 'Write more!!! do more!! with JavaScript',
          icon: 'javascript_4kx4k.4kimage',
        },
      });
    } else {
      newDate.push({
        ...obj,
      });
    }
  });

  return newDate;
}

console.log(createNewDate(projects));

answered Nov 26, 2020 at 15:58

Max's user avatar

MaxMax

3633 silver badges4 bronze badges

We can change in the following way

const oldArray = [{username: gopal, age: 20}, {username: gopi, age: 21}]
const obj = {username: gopal, age: 25}
const result = oldArray.map(d => d.username === 'gopi' ? d.age = obj.age : d)

answered Nov 25, 2022 at 18:00

KARTHIKEYAN.A's user avatar

KARTHIKEYAN.AKARTHIKEYAN.A

16.7k6 gold badges115 silver badges130 bronze badges

Find the index first:

function getIndex(array, key, value) {
        var found = false;
        var i = 0;
        while (i<array.length && !found) {
          if (array[i][key]==value) {
            found = true;
            return i;
          }
          i++;
        }
      }

Then:

console.log(getIndex($scope.rides, "_id", id));

Then do what you want with this index, like:

$scope[returnedindex].someKey = «someValue»;

Note: please do not use for, since for will check all the array documents, use while with a stopper, so it will stop once it is found, thus faster code.

answered Nov 21, 2017 at 7:05

Here i am using angular js. In javascript you can use for loop to find.

    if($scope.bechval>0 &&$scope.bechval!=undefined)
    {

                angular.forEach($scope.model.benhmarkghamlest, function (val, key) {
                $scope.model.benhmarkghamlest[key].bechval = $scope.bechval;

            });
    }
    else {
        alert("Please sepecify Bechmark value");
    }

Lorelorelore's user avatar

Lorelorelore

3,2358 gold badges29 silver badges39 bronze badges

answered Dec 14, 2018 at 9:27

Hari Lakkakula's user avatar

You can create your specific function like the below, then use that everywhere you need.

var each    = (arr, func) => 
                Array.from(
                    (function* (){
                        var i = 0;
                        for(var item of arr)
                            yield func(item, i++);
                    })()
                );

Enjoy..

answered Oct 28, 2020 at 7:58

MiMFa's user avatar

MiMFaMiMFa

8449 silver badges13 bronze badges

1

upsert(array, item) { 
        const i = array.findIndex(_item => _item.id === item.id);
        if (i > -1) {
            let result = array.filter(obj => obj.id !== item.id);
            return [...result, item]
        }
        else {
            return [...array, item]
        };
    }

answered Nov 23, 2020 at 23:25

Aathi's user avatar

AathiAathi

2,2692 gold badges19 silver badges16 bronze badges

The easiest way is to do this

    var projects = [
{
    
    
    value: "jquery",
    label: "jQuery",
    desc: "the write less, do more, JavaScript library",
    icon: "jquery_32x32.png"
},
{
    value: "jquery-ui",
    label: "jQuery UI",
    desc: "the official user interface library for jQuery",
    icon: "jqueryui_32x32.png"
}];

projects.find(data => data.value === "jquery").label ="xxxx"

console.log("------------>",projects)

answered 2 days ago

Aram Zuhairi's user avatar

to update multiple items with the matches use:

_.chain(projects).map(item => {
      item.desc = item.value === "jquery-ui" ? "new desc" : item.desc;
      return item;
    })

answered May 4, 2016 at 23:12

abhisekpaul's user avatar

abhisekpaulabhisekpaul

4577 silver badges5 bronze badges

The code below comes from jQuery UI Autocomplete:

var projects = [
    {
        value: "jquery",
        label: "jQuery",
        desc: "the write less, do more, JavaScript library",
        icon: "jquery_32x32.png"
    },
    {
        value: "jquery-ui",
        label: "jQuery UI",
        desc: "the official user interface library for jQuery",
        icon: "jqueryui_32x32.png"
    },
    {
        value: "sizzlejs",
        label: "Sizzle JS",
        desc: "a pure-JavaScript CSS selector engine",
        icon: "sizzlejs_32x32.png"
    }
];

For example, I want to change the desc value of jquery-ui. How can I do that?

Additionally, is there a faster way to get the data? I mean give the object a name to fetch its data, just like the object inside an array? So it would be something like jquery-ui.jquery-ui.desc = ....

imjared's user avatar

imjared

18.6k3 gold badges48 silver badges71 bronze badges

asked Jan 14, 2011 at 9:59

qinHaiXiang's user avatar

qinHaiXiangqinHaiXiang

5,83112 gold badges46 silver badges60 bronze badges

4

It is quite simple

  • Find the index of the object using findIndex method.
  • Store the index in variable.
  • Do a simple update like this: yourArray[indexThatyouFind]
//Initailize array of objects.
let myArray = [
  {id: 0, name: "Jhon"},
  {id: 1, name: "Sara"},
  {id: 2, name: "Domnic"},
  {id: 3, name: "Bravo"}
],
    
//Find index of specific object using findIndex method.    
objIndex = myArray.findIndex((obj => obj.id == 1));

//Log object to Console.
console.log("Before update: ", myArray[objIndex])

//Update object's name property.
myArray[objIndex].name = "Laila"

//Log object to console again.
console.log("After update: ", myArray[objIndex])

Vega's user avatar

Vega

27.1k27 gold badges91 silver badges98 bronze badges

answered Jan 30, 2017 at 14:43

Umair Ahmed's user avatar

9

You have to search in the array like:

function changeDesc( value, desc ) {
   for (var i in projects) {
     if (projects[i].value == value) {
        projects[i].desc = desc;
        break; //Stop this loop, we found it!
     }
   }
}

and use it like

var projects = [ ... ];
changeDesc ( 'jquery-ui', 'new description' );

UPDATE:

To get it faster:

var projects = {
   jqueryUi : {
      value:  'lol1',
      desc:   'lol2'
   }
};

projects.jqueryUi.desc = 'new string';

(In according to Frédéric’s comment you shouldn’t use hyphen in the object key, or you should use «jquery-ui» and projects[«jquery-ui»] notation.)

answered Jan 14, 2011 at 10:05

Aston's user avatar

AstonAston

3,5821 gold badge20 silver badges18 bronze badges

4

The best solution, thanks to ES6.

This returns a new array with a replaced description for the object that contains a value equal to «jquery-ui».

const newProjects = projects.map(p =>
  p.value === 'jquery-ui'
    ? { ...p, desc: 'new description' }
    : p
);

Brett Hayes's user avatar

answered Aug 7, 2018 at 2:59

kintaro's user avatar

kintarokintaro

2,2832 gold badges16 silver badges16 bronze badges

6

Using map is the best solution without using extra libraries.(using ES6)

const state = [
{
    userId: 1,
    id: 100,
    title: "delectus aut autem",
    completed: false
},
{
    userId: 1,
    id: 101,
    title: "quis ut nam facilis et officia qui",
    completed: false
},
{
    userId: 1,
    id: 102,
    title: "fugiat veniam minus",
    completed: false
},
{
    userId: 1,
    id: 103,
    title: "et porro tempora",
    completed: true
}]

const newState = state.map(obj =>
    obj.id === "101" ? { ...obj, completed: true } : obj
);

OhhhThatVarun's user avatar

answered Sep 3, 2019 at 20:44

Ankit Kumar Rajpoot's user avatar

1

ES6 way, without mutating original data.

var projects = [
{
    value: "jquery",
    label: "jQuery",
    desc: "the write less, do more, JavaScript library",
    icon: "jquery_32x32.png"
},
{
    value: "jquery-ui",
    label: "jQuery UI",
    desc: "the official user interface library for jQuery",
    icon: "jqueryui_32x32.png"
}];

//find the index of object from array that you want to update
const objIndex = projects.findIndex(obj => obj.value === 'jquery-ui');

// Make sure to avoid incorrect replacement
// When specific item is not found
if (objIndex === -1) {
  return;
}

// make new object of updated object.   
const updatedObj = { ...projects[objIndex], desc: 'updated desc value'};

// make final new array of objects by combining updated object.
const updatedProjects = [
  ...projects.slice(0, objIndex),
  updatedObj,
  ...projects.slice(objIndex + 1),
];

console.log("original data=", projects);
console.log("updated data=", updatedProjects);

Konrad's user avatar

Konrad

17.9k4 gold badges29 silver badges58 bronze badges

answered May 24, 2018 at 8:03

Bimal Grg's user avatar

Bimal GrgBimal Grg

7,1422 gold badges24 silver badges21 bronze badges

0

You can use $.each() to iterate over the array and locate the object you’re interested in:

$.each(projects, function() {
    if (this.value == "jquery-ui") {
        this.desc = "Your new description";
    }
});

answered Jan 14, 2011 at 10:07

Frédéric Hamidi's user avatar

Frédéric HamidiFrédéric Hamidi

255k41 gold badges481 silver badges475 bronze badges

given the following data, we want to replace berries in the summerFruits list with watermelon.

const summerFruits = [
{id:1,name:'apple'}, 
{id:2, name:'orange'}, 
{id:3, name: 'berries'}];

const fruit = {id:3, name: 'watermelon'};

Two ways you can do this.

First approach:

//create a copy of summer fruits.
const summerFruitsCopy = [...summerFruits];

//find index of item to be replaced
const targetIndex = summerFruits.findIndex(f=>f.id===3); 

//replace the object with a new one.
summerFruitsCopy[targetIndex] = fruit;

Second approach: using map, and spread:

const summerFruitsCopy = summerFruits.map(fruitItem => 
fruitItem .id === fruit.id ? 
    {...summerFruits, ...fruit} : fruitItem );

summerFruitsCopy list will now return an array with updated object.

Fred's user avatar

Fred

8152 gold badges9 silver badges33 bronze badges

answered Oct 17, 2019 at 10:56

meol's user avatar

meolmeol

1,01111 silver badges7 bronze badges

1

you can use .find so in your example

   var projects = [
            {
                value: "jquery",
                label: "jQuery",
                desc: "the write less, do more, JavaScript library",
                icon: "jquery_32x32.png"
            },
            {
                value: "jquery-ui",
                label: "jQuery UI",
                desc: "the official user interface library for jQuery",
                icon: "jqueryui_32x32.png"
            },
            {
                value: "sizzlejs",
                label: "Sizzle JS",
                desc: "a pure-JavaScript CSS selector engine",
                icon: "sizzlejs_32x32.png"
            }
        ];

let project = projects.find((p) => {
    return p.value === 'jquery-ui';
});

project.desc = 'your value'

answered Jul 19, 2017 at 15:11

abe kur's user avatar

abe kurabe kur

2312 silver badges3 bronze badges

0

you need to know the index of the object you are changing. then its pretty simple

projects[1].desc= "new string";

answered Jan 14, 2011 at 10:04

elasticrash's user avatar

elasticrashelasticrash

1,1711 gold badge14 silver badges30 bronze badges

This is another answer involving find.
This relies on the fact that find:

  • iterates through every object in the array UNTIL a match is found
  • each object is provided to you and is MODIFIABLE

Here’s the critical Javascript snippet:

projects.find( function (p) {
    if (p.value !== 'jquery-ui') return false;
    p.desc = 'your value';
    return true;
} );

Here’s an alternate version of the same Javascript:

projects.find( function (p) {
    if (p.value === 'jquery-ui') {
        p.desc = 'your value';
        return true;
    }
    return false;
} );

Here’s an even shorter (and somewhat more evil version):

projects.find( p => p.value === 'jquery-ui' && ( p.desc = 'your value', true ) );

Here’s a full working version:

  let projects = [
            {
                value: "jquery",
                label: "jQuery",
                desc: "the write less, do more, JavaScript library",
                icon: "jquery_32x32.png"
            },
            {
                value: "jquery-ui",
                label: "jQuery UI",
                desc: "the official user interface library for jQuery",
                icon: "jqueryui_32x32.png"
            },
            {
                value: "sizzlejs",
                label: "Sizzle JS",
                desc: "a pure-JavaScript CSS selector engine",
                icon: "sizzlejs_32x32.png"
            }
        ];

projects.find( p => p.value === 'jquery-ui' && ( p.desc = 'your value', true ) );

console.log( JSON.stringify( projects, undefined, 2 ) );

answered May 4, 2020 at 6:51

Stephen Quan's user avatar

Stephen QuanStephen Quan

19.5k4 gold badges80 silver badges73 bronze badges

1

I think this way is better

const index = projects.findIndex(project => project.value==='jquery-ui');
projects[index].desc = "updated desc";

answered Feb 6, 2019 at 12:16

tsadkan yitbarek's user avatar

tsadkan yitbarektsadkan yitbarek

1,3302 gold badges11 silver badges26 bronze badges

1

const users = [
  { name: "Alex", age: 25 },
  { name: "John", age: 32 },
];

const newUsers = users.map((user) => ({
  ...user,
  age: user.age + 5, // just for example
}));

// newUsers = [
// {name:"Alex" , age:30},
// {name:"John , age:37}
// ]

answered Jun 24, 2021 at 16:17

Mohammadreza's user avatar

0

const state = [
{
    userId: 1,
    id: 100,
    title: "delectus aut autem",
    completed: false
},
{
    userId: 1,
    id: 101,
    title: "quis ut nam facilis et officia qui",
    completed: false
},
{
    userId: 1,
    id: 102,
    title: "fugiat veniam minus",
    completed: false
},
{
    userId: 1,
    id: 103,
    title: "et porro tempora",
    completed: true
}]

const newState = state.map(obj =>
    obj.id === "101" ? { ...obj, completed: true } : obj
);

answered Jul 9, 2022 at 7:20

Prachi Rajput's user avatar

1

Change value with conditions using for each loop

projects.forEach((p,index)=>{
    if(index === 1){
       p.value = "Updated jquery-ui"
    }
})

answered Sep 18, 2021 at 11:29

MD SHAYON's user avatar

// using higher-order functions to avoiding mutation
var projects = [
            {
                value: "jquery",
                label: "jQuery",
                desc: "the write less, do more, JavaScript library",
                icon: "jquery_32x32.png"
            },
            {
                value: "jquery-ui",
                label: "jQuery UI",
                desc: "the official user interface library for jQuery",
                icon: "jqueryui_32x32.png"
            },
            {
                value: "sizzlejs",
                label: "Sizzle JS",
                desc: "a pure-JavaScript CSS selector engine",
                icon: "sizzlejs_32x32.png"
            }
        ];

// using higher-order functions to avoiding mutation
index = projects.findIndex(x => x.value === 'jquery-ui');
[... projects.slice(0,index), {'x': 'xxxx'}, ...projects.slice(index + 1, projects.length)];

answered Sep 7, 2017 at 15:11

Leo Lanese's user avatar

Leo LaneseLeo Lanese

4604 silver badges5 bronze badges

2

try using forEach(item,index) helper

var projects = [
    {
        value: "jquery",
        label: "jQuery",
        desc: "the write less, do more, JavaScript library",
        icon: "jquery_32x32.png"
    },
    {
        value: "jquery-ui",
        label: "jQuery UI",
        desc: "the official user interface library for jQuery",
        icon: "jqueryui_32x32.png"
    },
    {
        value: "sizzlejs",
        label: "Sizzle JS",
        desc: "a pure-JavaScript CSS selector engine",
        icon: "sizzlejs_32x32.png"
    }
];

let search_to_change = 'jquery'

projects.forEach((item,index)=>{
   if(item.value == search_to_change )
      projects[index].desc = 'your description ' 
})

answered Jul 10, 2020 at 1:15

keroles Monsef's user avatar

let users = [
    {id: 1, name: 'Benedict'},
    {id: 2, name: 'Myles'},
    {id: 3, name: 'Happy'},
]

 users.map((user, index) => {
 if(user.id === 1){
  users[index] = {id: 1, name: 'Baba Benny'};    
 }
 
 return user
})


console.log(users)

What this code does is map over the object and then match the desired
with if statement,

if(user.id === 1) 

once there is match somewhere use its index to swap

 users[index] = {id: 1, name: 'Baba Benny'};

the object in the array and then return the modified array

answered Aug 17, 2021 at 11:04

mwangaben's user avatar

mwangabenmwangaben

8378 silver badges11 bronze badges

5

You can use map function —

const answers = this.state.answers.map(answer => {
  if(answer.id === id) return { id: id, value: e.target.value }
  return answer
})

this.setState({ answers: answers })

answered Jul 23, 2019 at 10:30

gandharv garg's user avatar

Here is a nice neat clear answer. I wasn’t 100% sure this would work but it seems to be fine. Please let me know if a lib is required for this, but I don’t think one is. Also if this doesn’t work in x browser please let me know. I tried this in Chrome IE11 and Edge they all seemed to work fine.

    var Students = [
        { ID: 1, FName: "Ajay", LName: "Test1", Age: 20},
        { ID: 2, FName: "Jack", LName: "Test2", Age: 21},
        { ID: 3, FName: "John", LName: "Test3", age: 22},
        { ID: 4, FName: "Steve", LName: "Test4", Age: 22}
    ]

    Students.forEach(function (Student) {
        if (Student.LName == 'Test1') {
            Student.LName = 'Smith'
        }
        if (Student.LName == 'Test2') {
            Student.LName = 'Black'
        }
    });

    Students.forEach(function (Student) {
        document.write(Student.FName + " " + Student.LName + "<BR>");
    });

Output should be as follows

Ajay Smith

Jack Black

John Test3

Steve Test4

answered Nov 10, 2020 at 22:49

Deathstalker's user avatar

Assuming you wanted to run a bit more complicated codes during the modification, you might reach for an if-else statement over the ternary operator approach

// original 'projects' array;
var projects = [
    {
        value: "jquery",
        label: "jQuery",
        desc: "the write less, do more, JavaScript library",
        icon: "jquery_32x32.png"
    },
    {
        value: "jquery-ui",
        label: "jQuery UI",
        desc: "the official user interface library for jQuery",
        icon: "jqueryui_32x32.png"
    },
    {
        value: "sizzlejs",
        label: "Sizzle JS",
        desc: "a pure-JavaScript CSS selector engine",
        icon: "sizzlejs_32x32.png"
    }
];
// modify original 'projects' array, and save modified array into 'projects' variable
projects = projects.map(project => {
// When there's an object where key 'value' has value 'jquery-ui'
    if (project.value == 'jquery-ui') {

// do stuff and set a new value for where object's key is 'value'
        project.value = 'updated value';

// do more stuff and also set a new value for where the object's key is 'label', etc.
        project.label = 'updated label';

// now return modified object
        return project;
    } else {
// just return object as is
        return project;
    }
});

// log modified 'projects' array
console.log(projects);

answered Feb 23, 2021 at 4:58

David_'s user avatar

We can also use Array’s map function to modify object of an array using Javascript.

function changeDesc(value, desc){
   projects.map((project) => project.value == value ? project.desc = desc : null)
}

changeDesc('jquery', 'new description')

answered Jul 27, 2017 at 4:43

Mahima Agrawal's user avatar

1

The power of javascript destructuring

const projects = [
  {
    value: 'jquery',
    label: 'jQuery',
    desc: 'the write less, do more, JavaScript library',
    icon: 'jquery_32x32.png',
    anotherObj: {
      value: 'jquery',
      label: 'jQuery',
      desc: 'the write less, do more, JavaScript library',
      icon: 'jquery_32x32.png',
    },
  },
  {
    value: 'jquery-ui',
    label: 'jQuery UI',
    desc: 'the official user interface library for jQuery',
    icon: 'jqueryui_32x32.png',
  },
  {
    value: 'sizzlejs',
    label: 'Sizzle JS',
    desc: 'a pure-JavaScript CSS selector engine',
    icon: 'sizzlejs_32x32.png',
  },
];

function createNewDate(date) {
  const newDate = [];
  date.map((obj, index) => {
    if (index === 0) {
      newDate.push({
        ...obj,
        value: 'Jquery??',
        label: 'Jquery is not that good',
        anotherObj: {
          ...obj.anotherObj,
          value: 'Javascript',
          label: 'Javascript',
          desc: 'Write more!!! do more!! with JavaScript',
          icon: 'javascript_4kx4k.4kimage',
        },
      });
    } else {
      newDate.push({
        ...obj,
      });
    }
  });

  return newDate;
}

console.log(createNewDate(projects));

answered Nov 26, 2020 at 15:58

Max's user avatar

MaxMax

3633 silver badges4 bronze badges

We can change in the following way

const oldArray = [{username: gopal, age: 20}, {username: gopi, age: 21}]
const obj = {username: gopal, age: 25}
const result = oldArray.map(d => d.username === 'gopi' ? d.age = obj.age : d)

answered Nov 25, 2022 at 18:00

KARTHIKEYAN.A's user avatar

KARTHIKEYAN.AKARTHIKEYAN.A

16.7k6 gold badges115 silver badges130 bronze badges

Find the index first:

function getIndex(array, key, value) {
        var found = false;
        var i = 0;
        while (i<array.length && !found) {
          if (array[i][key]==value) {
            found = true;
            return i;
          }
          i++;
        }
      }

Then:

console.log(getIndex($scope.rides, "_id", id));

Then do what you want with this index, like:

$scope[returnedindex].someKey = «someValue»;

Note: please do not use for, since for will check all the array documents, use while with a stopper, so it will stop once it is found, thus faster code.

answered Nov 21, 2017 at 7:05

Here i am using angular js. In javascript you can use for loop to find.

    if($scope.bechval>0 &&$scope.bechval!=undefined)
    {

                angular.forEach($scope.model.benhmarkghamlest, function (val, key) {
                $scope.model.benhmarkghamlest[key].bechval = $scope.bechval;

            });
    }
    else {
        alert("Please sepecify Bechmark value");
    }

Lorelorelore's user avatar

Lorelorelore

3,2358 gold badges29 silver badges39 bronze badges

answered Dec 14, 2018 at 9:27

Hari Lakkakula's user avatar

You can create your specific function like the below, then use that everywhere you need.

var each    = (arr, func) => 
                Array.from(
                    (function* (){
                        var i = 0;
                        for(var item of arr)
                            yield func(item, i++);
                    })()
                );

Enjoy..

answered Oct 28, 2020 at 7:58

MiMFa's user avatar

MiMFaMiMFa

8449 silver badges13 bronze badges

1

upsert(array, item) { 
        const i = array.findIndex(_item => _item.id === item.id);
        if (i > -1) {
            let result = array.filter(obj => obj.id !== item.id);
            return [...result, item]
        }
        else {
            return [...array, item]
        };
    }

answered Nov 23, 2020 at 23:25

Aathi's user avatar

AathiAathi

2,2692 gold badges19 silver badges16 bronze badges

The easiest way is to do this

    var projects = [
{
    
    
    value: "jquery",
    label: "jQuery",
    desc: "the write less, do more, JavaScript library",
    icon: "jquery_32x32.png"
},
{
    value: "jquery-ui",
    label: "jQuery UI",
    desc: "the official user interface library for jQuery",
    icon: "jqueryui_32x32.png"
}];

projects.find(data => data.value === "jquery").label ="xxxx"

console.log("------------>",projects)

answered 2 days ago

Aram Zuhairi's user avatar

to update multiple items with the matches use:

_.chain(projects).map(item => {
      item.desc = item.value === "jquery-ui" ? "new desc" : item.desc;
      return item;
    })

answered May 4, 2016 at 23:12

abhisekpaul's user avatar

abhisekpaulabhisekpaul

4577 silver badges5 bronze badges

var index = items.indexOf(3452);

if (index !== -1) {
    items[index] = 1010;
}

Also it is recommend you not use the constructor method to initialize your arrays. Instead, use the literal syntax:

var items = [523, 3452, 334, 31, 5346];

You can also use the ~ operator if you are into terse JavaScript and want to shorten the -1 comparison:

var index = items.indexOf(3452);

if (~index) {
    items[index] = 1010;
}

Sometimes I even like to write a contains function to abstract this check and make it easier to understand what’s going on. What’s awesome is this works on arrays and strings both:

var contains = function (haystack, needle) {
    return !!~haystack.indexOf(needle);
};

// can be used like so now:
if (contains(items, 3452)) {
    // do something else...
}

Starting with ES6/ES2015 for strings, and proposed for ES2016 for arrays, you can more easily determine if a source contains another value:

if (haystack.includes(needle)) {
    // do your thing
}

answered May 6, 2011 at 18:56

Eli's user avatar

EliEli

17.1k4 gold badges36 silver badges49 bronze badges

3

The Array.indexOf() method will replace the first instance. To get every instance use Array.map():

a = a.map(function(item) { return item == 3452 ? 1010 : item; });

Of course, that creates a new array. If you want to do it in place, use Array.forEach():

a.forEach(function(item, i) { if (item == 3452) a[i] = 1010; });

answered May 6, 2011 at 19:03

gilly3's user avatar

gilly3gilly3

86.4k25 gold badges143 silver badges174 bronze badges

4

My suggested solution would be:

items.splice(1, 1, 1010);

The splice operation will start at index 1, remove 1 item in the array (i.e. 3452), and will replace it with the new item 1010.

DannyMoshe's user avatar

DannyMoshe

5,6803 gold badges29 silver badges49 bronze badges

answered Sep 29, 2018 at 7:38

Shimon Agassi's user avatar

1

Answer from @gilly3 is great.

Replace object in an array, keeping the array order unchanged

I prefer the following way to update the new updated record into my array of records when I get data from the server. It keeps the order intact and quite straight forward one liner.

users = users.map(u => u.id !== editedUser.id ? u : editedUser);

var users = [
{id: 1, firstname: 'John', lastname: 'Ken'},
{id: 2, firstname: 'Robin', lastname: 'Hood'},
{id: 3, firstname: 'William', lastname: 'Cook'}
];

var editedUser = {id: 2, firstname: 'Michael', lastname: 'Angelo'};

users = users.map(u => u.id !== editedUser.id ? u : editedUser);

console.log('users -> ', users);

answered Jun 5, 2020 at 10:44

muasif80's user avatar

muasif80muasif80

5,2763 gold badges31 silver badges45 bronze badges

3

Use indexOf to find an element.

var i = items.indexOf(3452);
items[i] = 1010;

BuZZ-dEE's user avatar

BuZZ-dEE

5,51410 gold badges65 silver badges94 bronze badges

answered May 6, 2011 at 18:55

Tesserex's user avatar

TesserexTesserex

17.1k5 gold badges65 silver badges105 bronze badges

1

First method

Best way in just one line to replace or update item of array

array.splice(array.indexOf(valueToReplace), 1, newValue)

Eg:

let items = ['JS', 'PHP', 'RUBY'];

let replacedItem = items.splice(items.indexOf('RUBY'), 1, 'PYTHON')

console.log(replacedItem) //['RUBY']
console.log(items) //['JS', 'PHP', 'PYTHON']

Second method

An other simple way to do the same operation is :

items[items.indexOf(oldValue)] = newValue

answered Feb 8, 2020 at 22:31

Goms's user avatar

GomsGoms

2,3444 gold badges19 silver badges36 bronze badges

1

Easily accomplished with a for loop.

for (var i = 0; i < items.length; i++)
    if (items[i] == 3452)
        items[i] = 1010;

answered May 6, 2011 at 18:55

mellamokb's user avatar

mellamokbmellamokb

55.8k12 gold badges108 silver badges136 bronze badges

1

If using a complex object (or even a simple one) and you can use es6, Array.prototype.findIndex is a good one. For the OP’s array, they could do,

const index = items.findIndex(x => x === 3452)
items[index] = 1010

For more complex objects, this really shines. For example,

const index = 
    items.findIndex(
       x => x.jerseyNumber === 9 && x.school === 'Ohio State'
    )

items[index].lastName = 'Utah'
items[index].firstName = 'Johnny'

answered Dec 28, 2018 at 0:14

Yatrix's user avatar

YatrixYatrix

13.1k15 gold badges46 silver badges78 bronze badges

1

You can edit any number of the list using indexes

for example :

items[0] = 5;
items[5] = 100;

Vamshi's user avatar

Vamshi

9,1044 gold badges37 silver badges54 bronze badges

answered May 6, 2011 at 18:56

VirtualTroll's user avatar

VirtualTrollVirtualTroll

3,0171 gold badge28 silver badges46 bronze badges

0

ES6 way:

const items = Array(523, 3452, 334, 31, ...5346);

We wanna replace 3452 with 1010, solution:

const newItems = items.map(item => item === 3452 ? 1010 : item);

Surely, the question is for many years ago and for now I just prefer to use immutable solution, definitely, it is awesome for ReactJS.

For frequent usage I offer below function:

const itemReplacer = (array, oldItem, newItem) =>
  array.map(item => item === oldItem ? newItem : item);

answered Feb 22, 2020 at 20:22

AmerllicA's user avatar

AmerllicAAmerllicA

26.7k14 gold badges125 silver badges148 bronze badges

A functional approach to replacing an element of an array in javascript:

const replace = (array, index, ...items) => [...array.slice(0, index), ...items, ...array.slice(index + 1)];

answered Nov 28, 2020 at 3:26

bmaggi's user avatar

bmaggibmaggi

2,8281 gold badge18 silver badges16 bronze badges

The immutable way to replace the element in the list using ES6 spread operators and .slice method.

const arr = ['fir', 'next', 'third'], item = 'next'

const nextArr = [
  ...arr.slice(0, arr.indexOf(item)), 
  'second',
  ...arr.slice(arr.indexOf(item) + 1)
]

Verify that works

console.log(arr)     // [ 'fir', 'next', 'third' ]
console.log(nextArr) // ['fir', 'second', 'third']

answered Jun 19, 2019 at 12:53

Purkhalo Alex's user avatar

1

Replacement can be done in one line:

var items = Array(523, 3452, 334, 31, 5346);

items[items.map((e, i) => [i, e]).filter(e => e[1] == 3452)[0][0]] = 1010

console.log(items);

Or create a function to reuse:

Array.prototype.replace = function(t, v) {
    if (this.indexOf(t)!= -1)
        this[this.map((e, i) => [i, e]).filter(e => e[1] == t)[0][0]] = v;
  };

//Check
var items = Array(523, 3452, 334, 31, 5346);
items.replace(3452, 1010);
console.log(items);

answered Jan 22, 2019 at 13:17

Artee's user avatar

ArteeArtee

8048 silver badges18 bronze badges

var items = Array(523,3452,334,31,5346);

If you know the value then use,

items[items.indexOf(334)] = 1010;

If you want to know that value is present or not, then use,

var point = items.indexOf(334);

if (point !== -1) {
    items[point] = 1010;
}

If you know the place (position) then directly use,

items[--position] = 1010;

If you want replace few elements, and you know only starting position only means,

items.splice(2, 1, 1010, 1220);

for more about .splice

answered Apr 26, 2015 at 3:10

KarSho's user avatar

KarShoKarSho

5,70113 gold badges44 silver badges78 bronze badges

The easiest way is to use some libraries like underscorejs and map method.

var items = Array(523,3452,334,31,...5346);

_.map(items, function(num) {
  return (num == 3452) ? 1010 : num; 
});
=> [523, 1010, 334, 31, ...5346]

answered Feb 11, 2014 at 21:35

mrded's user avatar

mrdedmrded

4,4242 gold badges32 silver badges36 bronze badges

0

If you want a simple sugar sintax oneliner you can just:

(elements = elements.filter(element => element.id !== updatedElement.id)).push(updatedElement);

Like:

let elements = [ { id: 1, name: 'element one' }, { id: 2, name: 'element two'} ];
const updatedElement = { id: 1, name: 'updated element one' };

If you don’t have id you could stringify the element like:

(elements = elements.filter(element => JSON.stringify(element) !== JSON.stringify(updatedElement))).push(updatedElement);

answered May 18, 2020 at 11:48

Marco Silva's user avatar

Marco SilvaMarco Silva

5545 silver badges14 bronze badges

var index = Array.indexOf(Array value);
        if (index > -1) {
          Array.splice(index, 1);
        }

from here you can delete a particular value from array and based on the same index
you can insert value in array .

 Array.splice(index, 0, Array value);

answered Aug 17, 2019 at 13:06

Gunjan Kumar's user avatar

Well if anyone is interresting on how to replace an object from its index in an array, here’s a solution.

Find the index of the object by its id:

const index = items.map(item => item.id).indexOf(objectId)

Replace the object using Object.assign() method:

Object.assign(items[index], newValue)

answered Feb 20, 2020 at 9:19

faye.babacar78's user avatar

1

 items[items.indexOf(3452)] = 1010

great for simple swaps. try the snippet below

const items = Array(523, 3452, 334, 31, 5346);
console.log(items)

items[items.indexOf(3452)] = 1010
console.log(items)

answered Oct 29, 2020 at 18:54

WhooNo's user avatar

WhooNoWhooNo

8212 gold badges11 silver badges26 bronze badges

Here is the basic answer made into a reusable function:

function arrayFindReplace(array, findValue, replaceValue){
    while(array.indexOf(findValue) !== -1){
        let index = array.indexOf(findValue);
        array[index] = replaceValue;
    }
}

answered Mar 13, 2018 at 21:43

JohnP2's user avatar

JohnP2JohnP2

1,83118 silver badges17 bronze badges

1

Here’s a one liner. It assumes the item will be in the array.

var items = [523, 3452, 334, 31, 5346]
var replace = (arr, oldVal, newVal) => (arr[arr.indexOf(oldVal)] = newVal, arr)
console.log(replace(items, 3452, 1010))

answered May 7, 2020 at 21:42

Alex Cory's user avatar

Alex CoryAlex Cory

9,7807 gold badges51 silver badges62 bronze badges

const items = Array(1, 2, 3, 4, 5);
console.log(items)

items[items.indexOf(2)] = 1010
console.log(items)

answered Apr 20, 2022 at 9:57

Raj Shah's user avatar

Raj ShahRaj Shah

5981 gold badge8 silver badges23 bronze badges

First, rewrite your array like this:

var items = [523,3452,334,31,...5346];

Next, access the element in the array through its index number. The formula to determine the index number is: n-1

To replace the first item (n=1) in the array, write:

items[0] = Enter Your New Number;

In your example, the number 3452 is in the second position (n=2). So the formula to determine the index number is 2-1 = 1. So write the following code to replace 3452 with 1010:

items[1] = 1010;

Jon Saw's user avatar

Jon Saw

7,1895 gold badges50 silver badges57 bronze badges

answered May 22, 2017 at 23:35

Anthony Levato's user avatar

I solved this problem using for loops and iterating through the original array and adding the positions of the matching arreas to another array and then looping through that array and changing it in the original array then return it, I used and arrow function but a regular function would work too.

var replace = (arr, replaceThis, WithThis) => {
    if (!Array.isArray(arr)) throw new RangeError("Error");
    var itemSpots = [];
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] == replaceThis) itemSpots.push(i);
    }

    for (var i = 0; i < itemSpots.length; i++) {
        arr[itemSpots[i]] = WithThis;
    }

    return arr;
};

answered Oct 29, 2018 at 16:01

J. Svec's user avatar

presentPrompt(id,productqty) {
    let alert = this.forgotCtrl.create({
      title: 'Test',
      inputs: [
        {
          name: 'pickqty',
          placeholder: 'pick quantity'
        },
        {
          name: 'state',
          value: 'verified',
          disabled:true,
          placeholder: 'state',

        }
      ],
      buttons: [
        {
          text: 'Ok',
          role: 'cancel',
          handler: data => {

            console.log('dataaaaname',data.pickqty);
            console.log('dataaaapwd',data.state);


          for (var i = 0; i < this.cottonLists.length; i++){

            if (this.cottonLists[i].id == id){
                this.cottonLists[i].real_stock = data.pickqty;

            }
          }

          for (var i = 0; i < this.cottonLists.length; i++){

            if (this.cottonLists[i].id == id){
              this.cottonLists[i].state = 'verified';   

          }
        }
            //Log object to console again.
            console.log("After update: ", this.cottonLists)
            console.log('Ok clicked');
          }
        },

      ]
    });
    alert.present();
  }

As per your requirement you can change fields and array names.
thats all. Enjoy your coding.

answered Aug 27, 2019 at 6:11

mahendren's user avatar

mahendrenmahendren

1,07411 silver badges8 bronze badges

The easiest way is this.

var items = Array(523,3452,334,31, 5346);
var replaceWhat = 3452, replaceWith = 1010;
if ( ( i = items.indexOf(replaceWhat) ) >=0 ) items.splice(i, 1, replaceWith);

console.log(items);
>>> (5) [523, 1010, 334, 31, 5346]

answered Aug 31, 2019 at 14:09

Vladimir Prudnikov's user avatar

1

When your array have many old item to replace new item, you can use this way:

function replaceArray(array, oldItem, newItem) {
    for (let i = 0; i < array.length; i++) {
        const index = array.indexOf(oldItem);
        if (~index) {
            array[index] = newItem;
        }
    }
    return array
}

console.log(replaceArray([1, 2, 3, 2, 2, 8, 1, 9], 2, 5));
console.log(replaceArray([1, 2, 3, 2, 2, 8, 1, 9], 2, "Hi"));

answered Dec 12, 2021 at 8:24

Amir Kangarloo's user avatar

This will do the job

Array.prototype.replace = function(a, b) {
    return this.map(item => item == a ? b : item)
}

Usage:

let items = ['hi', 'hi', 'hello', 'hi', 'hello', 'hello', 'hi']
console.log(items.replace('hello', 'hi'))

Output:

['hi', 'hi', 'hi', 'hi', 'hi', 'hi', 'hi']

The nice thing is, that EVERY array will have .replace() property.

answered Apr 7, 2022 at 10:39

Krzysiek's user avatar

1

  1. Replace Object in an Array Using the Index in JavaScript
  2. Replace Object in an Array Using the Splice Method in JavaScript

Replace Object in an Array in JavaScript

This article will tackle how to replace the different objects stored in the array in JavaScript easily because JavaScript is a dynamic language.

In JavaScript, the objects and the type in an array are dynamic or can change. We can store different object types in an array.

Replace Object in an Array Using the Index in JavaScript

By knowing the object’s index, we can easily replace any object in an array. It is one of the most common ways to replace the objects in the array in JavaScript.

Let’s understand this using a simple example.

In the code below, we created an array named selectedColors, and we stored five objects with a similar type.

Example code:

let selectedColors = ['Red', 'Blue', 'Orange', 'Black', 'Pink'];
console.log(selectedColors);

Output:

[ 'Red', 'Blue', 'Orange', 'Black', 'Pink' ]

Suppose we want to replace the first two objects with different colors names in the array. We can do that using the index of these objects.

At index 0, we have Red, and at index 1, we have Blue. We can replace these two colors using selectedColors[], give the index number of the object we want to replace, and assign a new color.

Example code:

let selectedColors = ['Red', 'Blue', 'Orange', 'Black', 'Pink'];
selectedColors[0] = 'Green';
selectedColors[1] = 'White';
console.log(selectedColors);

Output:

[ 'Green', 'White', 'Orange', 'Black', 'Pink' ]

As we can see in the code, we used selectedColors[0] = 'Green'; which means we assign the Green at index 0, and again we use the same procedure for selectedColors[1] = 'White'; where we give White at index 1.

After running the code, Red and Blue are replaced by Green and White, respectively. In the output, we have Green now at index 0 and White at index 1.

Replace Object in an Array Using the Splice Method in JavaScript

Another way to replace the object in an array in JavaScript is to use the splice method. The splice method allows us to update the array’s objects by removing or replacing existing elements in an array at the desired index.

If we want to replace an object in an array, we will need its index first.

Let’s understand how this method works by the following example.

Example code:

let monthNames = ["January", "March", "April", "June"];
monthNames.splice(1, 0, "February");
console.log("February is added in the list ", monthNames);
monthNames.splice(4, 1, "May");
console.log("June is replaced by May ", monthNames);

Output:

February is added in the list  [ 'January', 'February', 'March', 'April', 'June' ]
June is replaced by May  [ 'January', 'February', 'March', 'April', 'May' ]

First, we created an array named monthNames and stored the month’s names.

After that, we applied the splice() method on the array by using monthNames.splice(1, 0, "February");. This resulted in the new element February at index 1 without removing any element in the array.

The 1, 0, "February" in the mothNames.splice() means adding a new element at index 1, and 0 means we are not removing any element in the array.

We applied another splice() method on the resulted array after the first splice() using monthNames.splice(4, 1, "May"); to replace the element June which is at index 4 by the new element May.

In monthNames.splice(4, 1, "May");, the 4, 1 means that we want to replace the element at index 4 with May, and 1 means removing one element from the index 4.

In the output, the element June is replaced by the new element May at index 4. This is how we can use the splice() method to replace any object in an array in JavaScript.

В предыдущих статьях были рассмотрены примеры кода для добавления и удаления объектов из массивов:

  • Форма добавления в массив объектов в стейтах React
  • Форма удаления объекта из массива в стейтах React

В этой статье продолжим работать с объектами внутри массивов и рассмотрим пример кода для их изменения.

Для начала возьмём заготовку из предыдущих статей и внесём небольшое изменение. Добавим три поля для вывода свойств объекта. В этих полях можно будет редактировать свойства. А под полями ввода будет кнопка для сохранения изменений.

Выбор нужного объекта для изменения его свойств будет происходить по клику на кнопку в нужной строке с выводом свойств объекта. При этом в отдельный стейт будет сохраняться сохраняться id элемента, который сейчас редактируется. А если в текйщий момент никакой объект не редактируется, то в этот стейт будет записано «null» значение.

Попробуем написать такой код:

const mouseText = [
   {
      id: 'tl2zI5J3IbLwukybTEsIxXXb6',
      prop1: 'Тише',
      prop2: 'мыши',
      prop3: 'кот на крыше',
   },
   {
      id: 'ViWgVtvU2qRo6huLg18DdYuio',
      prop1: 'А котята',
      prop2: 'ещё',
      prop3: 'выше',
   },
];

import React, { useState } from 'react';

function App() {
   const [objArr, setValue] = useState(mouseText);
   const [idToEdit, setIdToEdit] = useState(null); // id объекта, который сейчас редактируется
 
   function getValue(prop, event) { // получение значения свойства
      return objArr.reduce((res, obj) => {
         if (obj.id == idToEdit) {
            return obj[prop];
         } else {
            return res;
         },
      }, '');
   }

   function change(prop, event) { // изменение input поля
      setValue(objArr.map(obj => {
         if (obj.id == idToEdit) {
            return {...obj, [prop]: event.target.value};
         } else {
            return obj;
         }
      }));
   }
   
   const result = objArr.map((obj) => {
      return <p key={obj.id}>
         {obj.prop1}
         {obj.prop2}
         {obj.prop3}

         <button onClick={() => setIdToEdit(obj.id)}>Изменить</button>
      </p>;
   });

   return <div>
      {result}

      <br /> 
      <input value={getValue('prop1')} onChange={event => change('prop1', event)} /> 
      <input value={getValue('prop2')} onChange={event => change('prop2', event)} /> 
      <input value={getValue('prop3')} onChange={event => change('prop3', event)} /> 
      
      <br /> 
      <button onClick={setIdToEdit(null)}>Сохранить изменения</button>
   </div>;
}

export default App;

Код функций плучился громоздким. Попробуем сократить его. Получится так:

function App() {
   const [objArr, setValue] = useState(mouseText);
   const [idToEdit, setIdToEdit] = useState(null); // id объекта, который сейчас редактируется
 
   function getValue(prop, event) { // получение значения свойства
      return objArr.reduce(
         (res, obj) => obj.id == idToEdit ? obj[prop] : res
      , ''); 
   }

   function change(prop, event) { // изменение input поля
      setValue(objArr.map(obj =>
         obj.id == idToEdit ? {...obj, [prop]: event.target.value} : obj 
      ));
   }
   
   const result = objArr.map((obj) => {
      return <p key={obj.id}>
         {obj.prop1}
         {obj.prop2}
         {obj.prop3}

         <button onClick={() => setIdToEdit(obj.id)}>Изменить</button>
      </p>;
   });

   return <div>
      {result}

      <br /> 
      <input value={getValue('prop1')} onChange={event => change('prop1', event)} /> 
      <input value={getValue('prop2')} onChange={event => change('prop2', event)} /> 
      <input value={getValue('prop3')} onChange={event => change('prop3', event)} /> 
      
      <br /> 
      <button onClick={setIdToEdit(null)}>Сохранить изменения</button>
   </div>;
}

Была ли статья полезной?

Была ли эта статья полезна?

Есть вопрос?

хостинг для сайтов

Закажите недорогой хостинг

Заказать

всего от 290 руб

Мутация в JavaScript – это изменение объекта или массива без создания новой переменной и переприсваивания значения. Например, вот так:

        const puppy = {
  name: 'Dessi',
  age: 9
};
puppy.age = 10;

    

Оригинальный объект puppy мутировал: мы изменили значение поля age.

Проблемы с мутациями

Казалось бы – ничего страшного. Но такие маленькие изменения могут приводить к большим проблемам.

        function printSortedArray(array) {
  array.sort();
  for (const item of array) {
    console.log(item);
  }
}

    

Когда мы вызываем функцию с названием printSortedArray, то обычно не думаем о том, что она что-то сделает с полученными данными. Но здесь встроенный метод массива sort() изменяет оригинальный массив. Так как массивы в JavaScript передаются по ссылке, то последующие операции будут иметь дело с обновленным, отсортированным порядком элементов.

Подобные ошибки трудно заметить, ведь операции выполняются нормально – только с результатом что-то не так. Функция рассчитывает на один аргумент, а получает «мутанта» – результат работы другой функции.

Решением являются иммутабельные (неизменяемые) структуры данных. Эта концепция предусматривает создание нового объекта для каждого обновления.

Если у вас есть 9-месячный puppy, который внезапно подрос, придется записать его в новую переменную grownUpPuppy.

К сожалению, иммутабельность из коробки в JavaScript не поддерживается. Существующие решения – это более или менее кривые костыли. Но если вы будете максимально избегать мутаций в коде, код станет понятнее и надежнее.

Помните!

Ключевое слово const в JavaScript защищает от изменения переменную, но не ее значение! Вы не сможете присвоить этой переменной другой объект, но вполне можете изменить поля оригинального объекта.

Избегайте мутирующих операций

Проблема

Распространенная мутация в JavaScript – изменение объекта:

        function parseExample(content, lang, modifiers) {
  const example = {
    content,
    lang
  };

  if (modifiers) {
    if (hasStringModifiers(modifiers)) {
      example.settings = modifiers
        .split(' ')
        .reduce((obj, modifier) => {
          obj[modifier] = true;
          return obj;
        }, {});
    } else {
      try {
        example.settings = JSON.parse(modifiers);
      } catch (err) {
        return {
          error: `Cannot parse modifiers`
        };
      }
    }
  }

  return example;
}
    

В этом примере мы создаем объект с тремя полями, поле settings опционально. Для добавления объекта мы мутируем исходный объект example – добавляем новое свойство. Чтобы понять, как выглядит в итоге объект example со всеми возможными вариациями, нужно просмотреть всю функцию. Было бы удобнее видеть его целиком в одном месте.

Решение

В большинстве кейсов отсутствующее поле в объекте заменимо полем со значением undefined.

В примере также присутствует конструкция try-catch, из которой в случае ошибки возвращается объект с совершенно другой структурой и единственным полем error. Это особый случай – объекты абсолютно разные, нет необходимости их объединять.

Чтобы очистить код, вынесем вычисление settings в отдельную функцию:

        function getSettings(modifiers) {
  if (!modifiers) {
    return undefined;
  }

  if (hasStringModifiers(modifiers)) {
    return modifiers.split(' ').reduce((obj, modifier) => {
      obj[modifier] = true;
      return obj;
    }, {});
  }

  return JSON.parse(modifiers);
}

function parseExample(content, lang, modifiers) {
  try {
    return {
      content,
      lang,
      settings: getSettings(modifiers)
    };
  } catch (err) {
    return {
      error: `Cannot parse modifiers`
    };
  }
}

    

Теперь проще понять и что делает фрагмент, и форму возвращаемого объекта. Благодаря рефакторингу мы избавились от мутаций и уменьшили вложенность.

Будьте осторожны с мутирующими методами массивов

Далеко не все методы в JavaScript возвращают новый массив или объект. Многие мутируют оригинальное значение прямо на месте. Например, push() – один из самых часто используемых.

Проблема

Посмотрим на этот код:

        const generateOptionalRows = () => {
  const rows = [];

  if (product1.colors.length + product2.colors.length > 0) {
    rows.push({
      row: 'Colors',
      product1: <ProductOptions options={product1.colors} />,
      product2: <ProductOptions options={product2.colors} />
    });
  }

  if (product1.sizes.length + product2.sizes.length > 0) {
    rows.push({
      row: 'Sizes',
      product1: <ProductOptions options={product1.sizes} />,
      product2: <ProductOptions options={product2.sizes} />
    });
  }

  return rows;
};

const rows = [
  {
    row: 'Name',
    product1: <Text>{product1.name}</Text>,
    product2: <Text>{product2.name}</Text>
  },
  // More rows...
  ...generateOptionalRows()
];

    

Здесь описаны два пути определения строк таблицы: массив с постоянными значениями и функция, возвращающая строки для опциональных данных. Внутри последней происходит мутация оригинального массива с помощью метода .push().

Сама по себе мутация – не такая уж большая проблема. Но где мутации, там и другие подводные камни. Проблема этого фрагмента – императивное построение массива и различные способы обработки постоянных и опциональных строк.

Решение

Одна из полезных техник рефакторинга – замена императивного кода, полного циклов и условий, на декларативный. Давайте объединим все возможные ряды в единый декларативный массив:

        const rows = [
  {
    row: 'Name',
    product1: <Text>{product1.name}</Text>,
    product2: <Text>{product2.name}</Text>
  },
  // More rows...
  {
    row: 'Colors',
    product1: <ProductOptions options={product1.colors} />,
    product2: <ProductOptions options={product2.colors} />,
    isVisible: (product1, product2) =>
      (product1.colors.length > 0 || product2.colors.length) > 0
  },
  {
    row: 'Sizes',
    product1: <ProductOptions options={product1.sizes} />,
    product2: <ProductOptions options={product2.sizes} />,
    isVisible: (product1, product2) =>
      (product1.sizes.length > 0 || product2.sizes.length) > 0
  }
];

const visibleRows = rows.filter(row => {
  if (typeof row.isVisible === 'function') {
    return row.isVisible(product1, product2);
  }
  return true;
});

    

Данные будут выведены в случае, если метод isVisible вернет значение true.

Код стал читаемее и удобнее для поддержки:

  • Всего один путь определения строки таблицы – не нужно решать, какой метод использовать.
  • Все данные в одном месте.
  • Легко редактировать строки, изменяя функцию isVisible.

Проблема

Вот другой пример:

        const defaults = { ...options };
const prompts = [];
const parameters = Object.entries(task.parameters);

for (const [name, prompt] of parameters) {
  const hasInitial = typeof prompt.initial !== 'undefined';
  const hasDefault = typeof defaults[name] !== 'undefined';

  if (hasInitial && !hasDefault) {
    defaults[name] = prompt.initial;
  }

  prompts.push({ ...prompt, name, initial: defaults[name] });
}

    

На первый взгляд, этот код не так уж плох. Он конвертирует объект в массив prompts путем добавления новых свойств. Но если взглянуть поближе, мы найдем еще одну мутацию внутри блока if – изменение объекта defaults. И вот это – уже большая проблема, которую сложно обнаружить.

Решение

Код выполняет две задачи внутри одного цикла:

  • конвертация объекта task.parameters в массив promts;
  • обновление объекта defaults значениями из task.parameters.

Для улучшения читаемости следует разделить операции:

        const parameters = Object.entries(task.parameters);

const defaults = parameters.reduce(
  (acc, [name, prompt]) => ({
    ...acc,
    [name]:
      prompt.initial !== undefined ? prompt.initial : options[name]
  }),
  {}
);

const prompts = parameters.map(([name, prompt]) => ({
  ...prompt,
  name,
  initial: defaults[name]
}));

    

***

Другие мутирующие методы массивов, которые следует использовать с осторожностью:

  • .copyWithin()
  • .fill()
  • .pop()
  • .push()
  • .reverse()
  • .shift()
  • .sort()
  • .splice()
  • .unshift()

Избегайте мутаций аргументов функции

Так как объекты и массивы в JavaScript передаются по ссылке, их изменение внутри функции приводит к неожиданным эффектам в глобальной области видимости.

        const mutate = object => {
  object.secret = 'Loves pizza';
};

const person = { name: 'Chuck Norris' };
mutate(person);
// -> { name: 'Chuck Norris', secret: 'Loves pizza' }

    

В этом фрагменте объект person изменяется внутри функции mutate.

Проблема

Подобные мутации могут быть и преднамеренными, и случайными. И то, и то приводит к проблемам:

  • Ухудшается читаемость кода. Функция не возвращает значение, а изменяет один из входящих параметров, становится непонятно, как ее использовать.
  • Ошибки, вызванные случайными изменениями, сложно заметить и отследить.

Рассмотрим пример:

        const addIfGreaterThanZero = (list, count, message) => {
  if (count > 0) {
    list.push({
      id: message,
      count
    });
  }
};

const getMessageProps = (
  adults,
  children,
  infants,
  youths,
  seniors
) => {
  const messageProps = [];
  addIfGreaterThanZero(messageProps, adults, 'ADULTS');
  addIfGreaterThanZero(messageProps, children, 'CHILDREN');
  addIfGreaterThanZero(messageProps, infants, 'INFANTS');
  addIfGreaterThanZero(messageProps, youths, 'YOUTHS');
  addIfGreaterThanZero(messageProps, seniors, 'SENIORS');
  return messageProps;
};

    

Этот код конвертирует набор числовых переменных в массив messageProps со следующей структурой:

        [
  {
    id: 'ADULTS',
    count: 7
  },
  {
    id: 'SENIORS',
    count: 2
  }
];

    

Проблема в том, что функция addIfGreateThanZero вызывает мутации массива, который мы ей передаем. Это изменение преднамеренное, оно необходимо для работы функции. Однако это не самое лучшее решение – можно создать более понятный и удобный интерфейс.

Решение

Давайте перепишем функцию, чтобы она возвращала новый массив:

        const addIfGreaterThanZero = (list, count, message) => {
  if (count > 0) {
    return [
      ...list,
      {
        id: message,
        count
      }
    ];
  }
  return list;
};

    

Но от этой функции можно полностью отказаться:

        const MESSAGE_IDS = [
  'ADULTS',
  'CHILDREN',
  'INFANTS',
  'YOUTHS',
  'SENIORS'
];
const getMessageProps = (
  adults,
  children,
  infants,
  youths,
  seniors
) => {
  return [adults, children, infants, youths, seniors]
    .map((count, index) => ({
      id: MESSAGE_IDS[index],
      count
    }))
    .filter(({ count }) => count > 0);
};

    

Этот код проще для понимания: в нем нет повторов и сразу понятен формат результата. Функция getMessageProps преобразует список значений в массив определенного формата, а затем отфильтровывает элементы с нулевым значением поля count.

Можно еще немного упростить:

        const MESSAGE_IDS = [
  'ADULTS',
  'CHILDREN',
  'INFANTS',
  'YOUTHS',
  'SENIORS'
];
const getMessageProps = (...counts) => {
  return counts
    .map((count, index) => ({
      id: MESSAGE_IDS[index],
      count
    }))
    .filter(({ count }) => count > 0);
};

    

Но это приводит к менее очевидному интерфейсу и не позволяет использовать автокомплит в редакторе кода.

Кроме того, создается ложное впечатление, что функция принимает любое количество аргументов и в любом порядке. Но это не так.

Вместо цепочки .map() + .filter() можно использовать встроенный метод массивов .reduce():

        const MESSAGE_IDS = [
  'ADULTS',
  'CHILDREN',
  'INFANTS',
  'YOUTHS',
  'SENIORS'
];
const getMessageProps = (...counts) => {
  return counts.reduce((acc, count, index) => {
    if (count > 0) {
      acc.push({
        id: MESSAGE_IDS[index],
        count
      });
    }
    return acc;
  }, []);
};

    

Однако код с reduce выглядит менее очевидным и труднее читается, поэтому стоило бы остановиться на предыдущем шаге рефакторинга.

***

Похоже, что единственная веская причина для мутации входящих параметров внутри функции – это оптимизация производительности. Если вы работаете с огромным объемом данных, то создание нового объекта/массива каждый раз – довольно затратная операция. Но как и с любой другой оптимизацией – не спешите, убедитесь, что проблема действительно существует. Не жертвуйте чистотой и ясностью кода.

Если вам нужны мутации, сделайте их явными

Проблема

Иногда мутаций не избежать, например, из-за неудачного API языка. Один из самых популярных примеров – метод массивов .sort().

        const counts = [6, 3, 2];
const puppies = counts.sort().map(n => `${n} puppies`);

    

Этот фрагмент кода создает ошибочное впечатление, что массив counts не изменяется, а просто создается новый массив puppies, внутри которого и происходит сортировка значений. Однако метод .sort() сортирует массив на месте – вызывает мутацию. Если разработчик не понимает этой особенности, в программе могут возникнуть ошибки, которые будет сложно отследить.

Решение

Лучше сделать мутацию явной:

        const counts = [6, 3, 2];
const sortedCounts = [...counts].sort();
const puppies = sortedCounts.map(n => `${n} puppies`);

    

Создается неглубокая копия массива counts, у которой и вызывается метод sort. Исходный массив, таким образом, остается неизменным.

Другой вариант – обернуть встроенные мутирующие операции кастомной функцией и использовать ее:

        function sort(array) {
  return [...array].sort();
}

const counts = [6, 3, 2];
const puppies = sort(counts).map(n => `${n} puppies`);

    

Также вы можете применять сторонние библиотеки, например, функцию sortBy библиотеки Lodash:

        const counts = [6, 3, 2];
const puppies = _.sortBy(counts).map(n => `${n} puppies`);

    

Обновление объектов

В современном JavaScript появились новые возможности, упрощающие реализацию иммутабельности – спасибо spread-синтаксису. До его появления нам приходилось писать что-то такое:

        const prev = { coffee: 1 };
const next = Object.assign({}, prev, { pizza: 42 });
// -> { coffee: 1, pizza: 42 }

    

Обратите внимание на пустой объект, передаваемый в качестве первого аргумента методу Object.assign(). Это исходное значение, которое и будет подвергаться мутациям (цель метода assign). Таким образом, этот метод и изменяет свой параметр, и возвращает его – крайне неудачный API языка.

Теперь можно писать проще:

        const prev = { coffee: 1 };
const next = { ...prev, pizza: 42 };

    

Суть та же, но гораздо менее многословно и без странного поведения.

А до введения стандарта ECMAScript 2015, который подарил нам Object.assign, избежать мутаций было и вовсе почти невозможно.

В документации библиотеки Redux есть замечательная страница Immutable Update Patterns, которая описывает концепцию обновления массивов и объектов без мутаций. Эта информация полезна, даже если вы не используете Redux.

Подводные камни методов обновления

Как бы ни был хорош spread-синтаксис, он тоже быстро становится громоздким:

        function addDrink(meals, drink) {
  return {
    ...meals,
    lunch: {
      ...meals.lunch,
      drinks: [...meals.lunch.drinks, drink]
    }
  };
}

    

Чтобы изменить глубоко вложенных полей, приходится разворачивать каждый уровень объекта, иначе мы потеряем данные:

        function addDrink(meals, drink) {
  return {
    ...meals,
    lunch: {
      drinks: [drink]
    }
  };
}

    

В этом фрагменте кода мы сохраняем только первый уровень свойств исходного объекта, а свойства lunch и drinks полностью переписываются.

И spread, и Object.assign осуществляют неглубокое клонирование – копируются только свойства первого уровня вложенности. Так что они не защищают от мутаций вложенных объектов или массивов.

Если вам приходится часто обновлять какую-то структуру данных, лучше сохранять для нее минимальный уровень вложенности.

Пока мы ждем появления в JavaScript иммутабельности из коробки, можно упростить себе жизнь двумя простыми способами:

  • Избегать мутаций.
  • Упростить обновление объектов.

Отслеживание мутаций

Линтинг

Один из способов отслеживать мутации – использование линтера кода. У ESLint есть несколько плагинов, которые занимаются именно этим. Например, eslint-plugin-better-mutation запрещает любые мутации, кроме локальных переменных внутри функций. Это отличная идея, которая позволяет предотвратить множество ошибок снаружи функции, но оставит большую гибкость внутри. Однако этот плагин часто ломается – даже в простых случаях вроде мутации в коллбэке метода .forEach().

ReadOnly

Другой способ – пометить все объекты и массивы как доступные только для чтения, если вы используете TypeScript или Flow.

Вот пример использования модификатора readonly в TypeScript:

        interface Point {
  readonly x: number;
  readonly y: number;
}

    

Использование служебного типа Readonly:

        type Point = Readonly<{
  readonly x: number;
  readonly y: number;
}>;

    

То же самое для массивов:

        function sort(array: readonly any[]) {
  return [...array].sort();
}

    

Модификатор readonly, и тип Readonly защищают от изменений только первый уровень свойств, так что их нужно отдельно добавлять к вложенным структурам.

В плагине eslint-plugin-functional есть правило, которое требует везде добавлять read-only типы. Его использование удобнее, чем их ручная расстановка. К сожалению, поддерживаются только модификаторы.

Еще удобнее был бы TypeScript флаг для дефолтной установки read-only типов с возможностью отката.

Заморозка

Чтобы сделать объекты доступными только для чтения во время выполнения, можно использовать метод Object.freeze. Он также работает только на один уровень вглубь. Для «заморозки» вложенных объектов используйте библиотеку вроде deep-freeze.

Упрощение изменений

Для достижения наилучшего результата следует сочетать технику предотвращения мутаций с упрощением обновления объектов.

Самый популярный инструмент для этого – библиотека Immutable.js:

        import { Map } from 'immutable';
const map1 = Map({ food: 'pizza', drink: 'coffee' });
const map2 = map1.set('drink', 'vodka');
// -> Map({ food: 'pizza', drink: 'vodka' })

    

Используйте ее, если вас не раздражает необходимость изучить новый API, а также постоянно преобразовывать обычные массивы и объекты в объекты Immutable.js и обратно.

Другой вариант – библиотека Immer. Она позволяет работать с объектом привычными методами, но перехватывает все операции и вместо мутации создает новый объект.

        import produce from 'immer';
const map1 = { food: 'pizza', drink: 'coffee' };
const map2 = produce(map1, draftState => {
  draftState.drink = 'vodka';
});
// -> { food: 'pizza', drink: 'vodka' }

    

Immer также замораживает полученный объект в процессе выполнения.

Иногда в мутациях нет ничего плохого

В некоторых (редких) случаях императивный код с мутациями не так уж и плох, и переписывание в декларативном стиле не сделает его лучше. Рассмотрим пример:

        const getDateRange = (startDate, endDate) => {
  const dateArray = [];
  let currentDate = startDate;
  while (currentDate <= endDate) {
    dateArray.push(currentDate);
    currentDate = addDays(currentDate, 1);
  }
  return dateArray;
};

    

Здесь мы создаем массив дат в заданном диапазоне. У вас есть идеи, как можно переписать этот код без императивного цикла, переприсваивания и мутаций?

В целом этот код имеет право на существование:

  • Все «плохие» операции изолированы внутри маленькой функции.
  • Понятное название функции само по себе описывает, что она делает.
  • Работа функции не влияет на внешнюю область видимости: она не использует глобальные переменные и не изменяет свои аргументы.

Лучше писать простой и чистый код с мутациями, чем сложный и запутанный без них!

Если вы используете мутации, постарайтесь изолировать их в маленькие чистые функции с понятными именами.

Руководство к действию

  1. Императивный код с мутациями сложнее читать и поддерживать, чем чистый декларативный код. Поэтому – рефакторьте!
  2. Сохраняйте полную форму объекта в одном месте и держите ее максимально чистой.
  3. Отделяйте логику «ЧТО» от логики «КАК».
  4. Изменения входных параметров функции приводит к незаметным, но очень неприятным ошибкам, которые трудно дебажить.
  5. Цепочка методов .map() + .filter() в большинстве случаев выглядит понятнее, чем один метод .reduce().
  6. Если вам очень хочется что-то мутировать, делайте это максимально явно. Старайтесь изолировать подобные операции в функции.
  7. Используйте техники для автоматического предотвращения мутаций.

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Как изменить массив автокад
  • Как изменить массив char c
  • Как изменить маску подсети на телефоне
  • Как изменить маску подсети на роутере
  • Как изменить маску подсети на андроид

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии