1
votes

Comment injecter des valeurs d'un tableau dans un objet en utilisant JavaScript?

Je voudrais extraire des valeurs d'un objet (done), qui sont placées dans un tableau (done), puis ces valeurs sont modifiées (par une bibliothèque d'interpolation) et me sont renvoyées sous forme de tableau de valeurs.

I souhaite réinsérer ces valeurs dans un objet de la même forme d'où elles proviennent.

Mais je suis coincé sur quelque chose d'assez basique, et certainement faisable.

I avoir un exemple d'état, comme ceci (cela pourrait être une forme totalement différente, ceci n'est qu'un exemple):

  // make sure tweened values are in an array
  var valuesArr = Array.isArray(tweenedValues) ? tweenedValues : [tweenedValues]
  // this object will hold tween values of current frame/progress, 
  // set to original state for now... we'll update it's values from 
  // valuesArr later
  var tweenedState = self.state
  // set the newState properties with new values from valuesArr
  // (newState is the state passed into the tweenState() method)
  Object.keys(newState).forEach((key, index) => {
    if (typeof newState[key] === "object") {
      Object.keys(newState[key]).forEach(key2 => {
        tweenedState[key][key2] = valuesArr[index]
      })
    } else {
      tweenedState[key] = valuesArr[index]
    }
  })
  console.log("tweenedState: ", tweenedState)

J'ai un nouvel état, dans lequel je veux passer ma méthode d'interpolation:

tweenedState = { 
  ignore: "me",
  count: 50.1231,
  foo: 34.43543,
  bar: {
    baz: 456.4543
  }
}

Il y a une bibliothèque d'interpolation dans la méthode tweenState , qui produit un tableau de ces valeurs à chaque "image" de l'animation :

// NOTE: I only pass in the properties I wanna tween!!

myApp.tweenState({ count: 100, foo: 50, bar: { baz: 999 } })

// internally, the tween lib produces something like this on each frame:

tweenedValues = [ 50.1231, 34.43543, 456.4543 ]

Je voudrais insérer ces valeurs interpolées dans un objet de la même forme que l'objet d'état que j'utilise, pour créer ceci sur chaque image (comme par exemple état ci-dessus):

var newState = { 
  count: 100,
  foo: 50,
  bar: {
    baz: 999
  }
}

... jusqu'à présent, je n'ai que ce terrible code (appelé sur chaque frame):

var state = { 
  ignore: "me",
  count: 0,
  foo: 10,
  bar: {
    baz: 99
  }
}

Qui a ces problèmes évidents:

  • non récursif, ne peut pas aller plus de 2 niveaux dans un objet
  • dans tous les cas, la ligne tweenedState [key] [key2] = valuesArr [index] ne définit pas la valeur comme prévu
  • quand je l'ai transformé en fonction récursive, il a bouclé pour toujours et s'est écrasé

J'ai donc besoin d'une fonction qui prend le tableau et insère les valeurs au bon endroit - à savoir les propriétés passées au début (ce qui crée l'objet tweenedState ).

EDIT: De toute évidence, l'objet d'état peut sembler totalement différent - celui donné n'est qu'un exemple - Il peut avoir plusieurs niveaux de profondeur, et peut contenir d'autres éléments NON transmis. Le point clé est que je me retrouve avec un objet d'état exactement comme l'original, mais avec les valeurs interpolées insérées à la place.

Et je le répète - la bibliothèque Tween crée le tableau de valeurs, pas moi, pas mon choix. Et oui, je sais que les propriétés des objets ne sont pas toujours dans le même ordre.

EDIT 2: ce code doit être isomorphe - fonctionne dans les navigateurs récents (ne se soucient pas d'IE) et em > Node 10 ou version ultérieure, idéalement sans polyfills ...

EDIT 3: MAINTENANT RÉSOLU:

NinaScholz et mashi ont fourni des réponses qui ont fonctionné pour moi (après avoir corrigé un bug ailleurs ).

Ninas answer a des exigences de version JS plus strictes, et est un peu moins portable que la réponse mashis. Sur cette base, j'ai accepté la réponse mashis, bien que la réponse de Ninas soit également très gentille.

Merci.


4 commentaires

voulez-vous vraiment utiliser un tableau de valeurs et un objet pour ajouter des valeurs dans un ordre qui n'est pas celui de l'objet? pourquoi ne pas utiliser un tableau de cibles supplémentaires au tableau valuse?


Vous le savez, c'est assez basique : tweenedState = {count: tweenedValues ​​[0], foo: tweenedValues ​​[1], bar: {baz: tweenedValues ​​[2]}};


Pourquoi utilisez-vous Object.keys () ? C'est "votre" état, vous devez donc en connaître les propriétés. Pourquoi ne pouvez-vous pas simplement faire: state.count = tweenedValues ​​[0]; ... ?


Andreas - parce qu'évidemment j'ai besoin de quelque chose qui peut gérer les états de n'importe quelle forme ... Donc Ibrahim votre réponse n'est pas bonne et Nina, je ne contrôle pas la bibliothèque Tween.


3 Réponses :


2
votes

Vous pouvez parcourir les entrées et appeler à nouveau la fonction pour les entrées imbriquées.

function setValues(pattern, values) {
    return Object.fromEntries(Object
        .entries(pattern)
        .map(([k, v]) => [
            k,
            v && typeof v === 'object'
                ? setValues(v, values)
                : values.length ? values.shift() : v
        ])
    );
}

var state = { count: 200, foo: 10, bar: { zzz: 999 }, ignore: "me" },
    tweenedValues = [50.1231, 34.43543, 456.4543],
    tweenedState = setValues(state, [...tweenedValues]);

console.log(tweenedState);


12 commentaires

J'obtiens TypeError: Object.fromEntries n'est pas une fonction , bien que cela ressemble à ce que je veux


quelle version js utilisez-vous?


ce code doit être isomorphe - fonctionnant dans un navigateur récent (ne se soucient pas d'IE) et Node 10 ou version ultérieure


il fonctionne dans les navigateurs .


Je sais que ... J'accepterai votre réponse et chercherai un petit polyfill Object.fromEntries pour Node. Merci.


js function fromEntries (iterable) {return [... iterable] .reduce ((obj, [key, val]) => {obj [key] = val return obj}, {})} J'ai utilisé ce "ponyfill" et remplacé Object.fromEntries par fromEntries , qui travaille maintenant dans Node 10. Merci.


En fait, cela ne fonctionne pas: / Cela ne fonctionne que si l'état d'origine contient ne contient que les propriétés en cours d'interpolation - il borks toutes les autres propriétés ... Supprimé comme réponse acceptée. Si l'état d'origine contient les éléments suivants {count: 200, foo: 10, bar: {zzz: 999}, ignorez: "me"} il se casse lorsque vous ne transmettez que {count: 200, toto: 10, barre: {zzz: 999}}


il suffit de vérifier si aucune autre valeur n'est disponible ... veuillez voir modifier.


Non ... Me donne {count: 200, foo: 10, ignore: 'meNaN', bar: {zzz: NaN}}


veuillez ajouter un objet plus grand et les valeurs d'application de l'annonce de résultat souhaité.


Remarque, j'ai mis à jour mon OP pour le rendre un peu plus clair, en ne passant que CERTAINS de l'état - seulement les bits qui doivent être interpolés .. Au cas où cela aiderait quiconque.


J'ai trouvé un bogue ailleurs dans l'interpolation, corrigé cela, puis votre version mise à jour a fonctionné pour moi, merci!



0
votes

comme je le vois, vous avez des valeurs dans un tableau qui sont toujours dans un ordre garanti, et vous les voulez comme valeurs de prop dans un objet ... vous pouvez utiliser la déstructuration d'objets

let obj = {count, foo, bar}

puis créez un objet comme celui-ci

const [count, foo, bar] = tweenedValues;


1 commentaires

Cela ne fait pas ce que je veux - la troisième valeur est au mauvais endroit



2
votes

function setTweenedValues(state, values) {
  const reducer = (newState, [key, val]) => {
    newState[key] = val;
    if (typeof val === "number") {
      newState[key] = values.shift();
    }
    if (typeof val === "object") {
      newState[key] = Object.entries(val).reduce(reducer, {});
    }

    return newState;
  };

  const newState = Object.entries(state).reduce(reducer, {});

  return newState;
}

var state = { count: 200, foo: 10, bar: { zzz: 999 }, ignore: "me" },
    tweenedValues = [50.1231, 34.43543, 456.4543],
    tweenedState = setTweenedValues(state, [...tweenedValues]);

console.log(tweenedState);


1 commentaires

J'accepterai cette réponse par rapport à la réponse de Ninas, seulement parce qu'elle est un peu plus petite, n'a pas besoin de Object.fromEntries et c'est un peu plus facile pour mon petit cerveau à comprendre .. Merci!