javascript - Hur man förhindrar objekt/array-mutation?


Jag har försökt felsöka ett konstigt problem och jag har äntligen listat ut varför det händer. Vet bara inte hur jag ska förhindra det (; Jag har den här funktionen:

getInfo(id) {
  id = id || "zero";
  let i = routeDefinitions.findIndex(r => Boolean(r.name.toLowerCase().match(id)));
  // console.log(i) - works in plunker
  // but in my app sometimes returns -1...
  let current = routeDefinitions[i];
  let next = routeDefinitions[i + 1] ? routeDefinitions[i + 1] : false;
  let prev = routeDefinitions[i - 1] ? routeDefinitions[i - 1] : false;
  return { prev, current, next };
}

..det fungerar perfekt i den här plunkern, men i min app använder jag dess returvärde för att uppdatera appens tillstånd (egen implementation av redux-mönstret). När jag skickar returvärdet genom den här funktionen:

  private _update(_old, _new) {
    let newState = Object.keys(_new)
      .map(key => {
        if (_old[key] === undefined) {
          _old[key] = _new[key];
        } else if (typeof _new[key] === "object") {
          this._update(_old[key], _new[key]);
        } else {
          _old[key] = _new[key];
        }
        return _old;
      })
      .find(Boolean);

    return Object.assign({}, newState || _old);
  }

..routeDefinitions-arrayen ändras och saker börjar gå sönder... Jag har försökt några saker:

let current = [...routeDefinitions][i];
// and:
return Object.assign({}, { prev, current, next });

..men det fungerade inte. Hur kan jag förhindra mutation av routeDefinitions-arrayen?

REDIGERA: Jag har lyckats återskapa felet i denna plunker

Svar #1

routeDefinitions-arrayen muteras och saker börjar gå sönder

Om din funktion verkligen är:

getInfo(id) {
  id = id || "zero";
  let i = routeDefinitions.findIndex(r => Boolean(r.name.toLowerCase().match(id)));
  // console.log(i) - works in plunker
  // but in my app sometimes returns -1...
  let current = routeDefinitions[i];
  let next = routeDefinitions[i + 1] ? routeDefinitions[i + 1] : false;
  let prev = routeDefinitions[i - 1] ? routeDefinitions[i - 1] : false;
  return { prev, current, next };
}

Då routeDefinitions ändras inte. Något annat ändrar routeDefinitions.

Svar #2

Jag löste detta genom att ändra _update() på detta sätt:

  private _update2(_old, _new) {
    let newState = {}; 
    Object.keys(_new)
      .map(key => {
        if (_old[key] === undefined) {
          newState[key] = _new[key];
        } else if (typeof _new[key] === "object") {
          newState[key] = this._update2(_old[key], _new[key]);
        } else {
          newState[key] = _new[key];
        }
        return newState;
      })
      .find(Boolean);

    return Object.assign({}, _old, newState);
  } 

Jag använder old state bara för att kontrollera värden, ändra det inte förrän senare när _update() är klar.

Plunker

Relaterade artiklar