Affectations de variables JavaScript à partir de tuples

99

Dans d'autres langages comme Python 2 et Python 3, vous pouvez définir et attribuer des valeurs à une variable de tuple et récupérer leurs valeurs comme ceci:

tuple = ("Bob", 24)
name, age = tuple
print(name)           #name evaluates to Bob
print(age)            #age evaluates to 24

Y a-t-il quelque chose de similaire dans JavaScript? Ou est-ce que je dois juste le faire de la manière laide avec un tableau:

tuple = ["Bob", 24]
name = tuple[0]       //name Evaluates to Bob
age = tuple[1]        //age Evaluates to 24

Existe-t-il un meilleur moyen de simuler des tuples Python dans JavaScript 5?

Mise à jour: voir la réponse concernant ES6, qui devrait être privilégiée par rapport à CoffeeScript pour les nouveaux projets.

Karl
la source
12
En JavaScript, n'oubliez pas de déclarer les variables:var tuple, name, age;
Šime Vidas
3
var name=tuple[0], age=tuple[1]; C'est un peu plus typé, mais laid pourrait être une exagération.
Brent Bradburn

Réponses:

120

Javascript 1.7 a ajouté une affectation déstructurée qui vous permet de faire essentiellement ce que vous recherchez.

function getTuple(){
   return ["Bob", 24];
}
var [a, b] = getTuple();
// a === "bob" , b === 24 are both true
pc1oad1etter
la source
5
Ce n'est pas du javascript basé sur des standards, mais plutôt des extensions spécifiques à Mozilla.
ninjagecko
14
@ninjagecko: "JavaScript" est l'implémentation de Mozilla, et les affectations de déstructuration feront partie du prochain standard ecmascript
Bergi
64
Il fait maintenant en fait partie de ES6.
Pier Paolo Ramon du
9
Après quelques années, ma réponse est devenue techniquement correcte mais pas utile à la fois pour la correction et l'utilité. Yay!
pc1oad1etter
49

Vous devez le faire de manière laide. Si vous voulez vraiment quelque chose comme ça, vous pouvez consulter CoffeeScript , qui a cela et beaucoup d'autres fonctionnalités qui le font ressembler davantage à python (désolé de le faire sonner comme une publicité, mais je l'aime vraiment.)

Gabi Purcaru
la source
Hmm, c'est assez intéressant, je viens de courir sur ce scénario moi-même, car JavaScript ne semble pas fournir un support évident de tuple, et venant d'une période intense de programmation fonctionnelle, vous développez le besoin de tuples. Je viens également de trouver ceci, mais je ne sais pas si cela fonctionne, cela avait l'air bien en termes de support de tuple aussi: cs.umd.edu/projects/PL/arrowlets/api-tuples.xhtml . Je vais certainement regarder CoffeeScript.
9codeMan9
29

Vous pouvez faire quelque chose de similaire:

var tuple = Object.freeze({ name:'Bob', age:14 })

puis faites référence au nom et à l'âge comme attributs

tuple.name 
tuple.age 
monika mevenkamp
la source
5
Je ne voterai pas contre mais techniquement, c'est incorrect. Vous pouvez toujours modifier (c'est-à-dire muter) les valeurs de tuple.name et tuple.age après la déclaration de l'objet. Par définition, les types immuables ne peuvent pas être modifiés une fois définis. Ils sont comme des types en lecture seule où les paramètres et leurs valeurs ne peuvent être déclarés qu'une seule fois.
Evan Plaice
4
@EvanPlaice si la mutabilité est un problème, vous pouvez utiliser Object.freeze(), à savoir:tuple = Object.freeze({ name:'Bob', age:14 })
canon
@canon Je suis d'accord, c'est probablement la seule approche acceptable / correcte dans tout ce fil. Malheureusement, la réponse de mcm ne gèle pas l'objet, il est donc toujours modifiable.
Evan Plaice
@EvanPlaice Je ne vois pas d'où vient le problème de la mutabilité - les tuples ne sont pas immuables dans l'exemple Python original!
Daniel Buckmaster
@DanielBuckmaster La différence entre une liste et un tuple en Python est qu'une liste est modifiable alors qu'un tuple ne l'est pas. Voir docs.python.org/2/tutorial/… . Les tuples ne sont pas pris en charge nativement dans JavaScript car toutes les structures de données JS sont modifiables sauf si vous appelez Object.freeze () sur l'objet après sa création.
Evan Plaice
27

Cette fonctionnalité "tuple" s'appelle la déstructuration dans EcmaScript2015 et sera bientôt prise en charge par des navigateurs à jour. Pour le moment, seuls Firefox et Chrome le prennent en charge .

Mais bon, tu peux utiliser un transpilateur .

Le code serait aussi beau que python:

let tuple = ["Bob", 24]
let [name, age] = tuple

console.log(name)
console.log(age)
Adrian
la source
2
Aux futurs lecteurs: cette fonctionnalité est prise en charge dans Chrome depuis Chrome 49 (selon la documentation de Mozilla). Vous pouvez également vérifier la compatibilité en utilisant la documentation de Mozilla ici: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jamie
12

Un tableau gelé se comporte de la même manière qu'un tuple python:

const tuple = Object.freeze(["Bob", 24]);
let [name, age]; = tuple
console.debug(name); // "Bob"
console.debug(age); // 24

Soyez chic et définissez une classe

class Tuple extends Array { 
  constructor(...items) { 
    super(...items); 
    Object.freeze(this);
  } 
}

let tuple = new Tuple("Jim", 35);
let [name, age] = tuple;
console.debug(name); // Jim
console.debug(age); // 35
tuple = ["Bob", 24]; // no effect 
console.debug(name); // Jim
console.debug(age); // 25

Fonctionne aujourd'hui dans tous les derniers navigateurs.

Matthew James Davis
la source
Ne pourriez-vous pas simplement le définir sur un const? Le const est immuable, non?
Mark A
2
Non. Le const n'est pas réaffectable. Vous ne pouvez pas faire const tuple = ["Jim", 35]; tuple = ["James", 35]. Vous pouvez faire const tuple = ["Jim", 35]; tuple [0] = "James"; Ce n'est donc pas immuable.
Matthew James Davis
6

Les tuples ne sont pas pris en charge dans JavaScript

Si vous recherchez une liste immuable, Object.freeze () peut être utilisé pour rendre un tableau immuable.

La méthode Object.freeze () fige un objet: c'est-à-dire empêche l'ajout de nouvelles propriétés; empêche les propriétés existantes d'être supprimées; et empêche les propriétés existantes, ou leur énumérabilité, leur configurabilité ou leur capacité d'écriture, d'être modifiées. En substance, l'objet est rendu effectivement immuable. La méthode renvoie l'objet gelé.

Source: Réseau de développeurs Mozilla - Object.freeze ()

Assignez un tableau comme d'habitude mais verrouillez-le en utilisant 'Object.freeze ()

> tuple = Object.freeze(['Bob', 24]);
[ 'Bob', 24 ]

Utilisez les valeurs comme vous le feriez pour un tableau normal (la multi-affectation python n'est pas prise en charge)

> name = tuple[0]
'Bob'
> age = tuple[1]
24

Tentative d'attribution d'une nouvelle valeur

> tuple[0] = 'Steve'
'Steve'

Mais la valeur n'est pas modifiée

> console.log(tuple)
[ 'Bob', 24 ]
Plie d'Evan
la source
Sur une note latérale, j'espère que Tuples bénéficiera d'un support de première classe dans ES6. Un véritable tuple natif (c'est-à-dire une séquence hétérogène) améliorera également la vitesse.
Evan Plaice
5

Malheureusement, vous ne pouvez pas utiliser cette syntaxe d'affectation de tuple dans le script (ECMA | Java).

EDIT: Quelqu'un lié à Mozilla / JS 1.7 - cela ne fonctionnerait pas entre les navigateurs, mais si ce n'est pas nécessaire, il y a votre réponse.

meder omuraliev
la source
3

Ce n'est pas destiné à être utilisé dans la vraie vie, juste un exercice intéressant. Voir Pourquoi l'utilisation de la fonction JavaScript eval est-elle une mauvaise idée?pour plus de détails.

C'est le plus proche que vous pouvez obtenir sans recourir aux extensions spécifiques au fournisseur:

myArray = [1,2,3];
eval(set('a,b,c = myArray'));

Fonction d'assistance:

function set(code) {
    var vars=code.split('=')[0].trim().split(',');
    var array=code.split('=')[1].trim();
    return 'var '+vars.map(function(x,i){return x+'='+array+'['+i+']'}).join(',');
}

Preuve que cela fonctionne dans une portée arbitraire:

(function(){
    myArray = [4,5,6];
    eval(set('x,y,z = myArray'));
    console.log(y);  // prints 5
})()

eval n'est pas pris en charge dans Safari.

ninjagecko
la source
5
+1 pour être super intelligent, ne l'utilisez jamais dans la vraie vie
:-p
3

Pour mettre à jour la réponse du ministre, vous pouvez maintenant le faire avec es2015:

function Tuple(...args) {
  args.forEach((val, idx) => 
    Object.defineProperty(this, "item"+idx, { get: () => val })
  )
}


var t = new Tuple("a", 123)
console.log(t.item0) // "a"
t.item0 = "b"
console.log(t.item0) // "a"

https://jsbin.com/fubaluwimo/edit?js,console

Zach Dahl
la source
Il n'y a aucune raison pour que vous ne puissiez pas faire cela avant ES2015 ... De plus, cela ne répond pas à la question du PO, il a demandé une déstructuration
ThatWeirdo
3

Vous pouvez également avoir un type de tuple en Javascript. Définissez-le simplement avec des fonctions d'ordre supérieur (le terme académique est l'encodage de l'Église):

const Tuple = (...args) => {
  const Tuple = f => f(...args);
  return Object.freeze(Object.assign(Tuple, args));
};

const get1 = tx => tx((x, y) => x);

const get2 = tx => tx((x, y) => y);

const bimap = f => g => tx => tx((x, y) => Tuple(f(x), g(y)));

const toArray = tx => tx((...args) => args);

// aux functions

const inc = x => x + 1;
const toUpperCase = x => x.toUpperCase();

// mock data

const pair = Tuple(1, "a");

// application

console.assert(get1(pair) === 1);
console.assert(get2(pair) === "a");

const {0:x, 1:y} = pair;
console.log(x, y); // 1 a

console.log(toArray(bimap(inc) (toUpperCase) (pair))); // [2, "A"]

const map = new Map([Tuple(1, "a"), Tuple(2, "b")]);
console.log(map.get(1), map.get(2)); // a b

Veuillez noter que ce Tuplen'est pas utilisé comme un constructeur normal. La solution ne repose pas du tout sur le système prototype, mais uniquement sur des fonctions d'ordre supérieur.

Quels sont les avantages des tuples par rapport aux Arrays utilisés comme des tuples? Les tuples encodés en église sont immuables par conception et empêchent ainsi les effets secondaires causés par les mutations. Cela permet de créer des applications plus robustes. De plus, il est plus facile de raisonner sur le code qui distingue Arrays en tant que type de collection (par exemple [a]) et les tuples en tant que données liées de différents types (par exemple (a, b)).


la source
1

Voici une implémentation simple de Javascript Tuple:

var Tuple = (function () {
   function Tuple(Item1, Item2) {
      var item1 = Item1;
      var item2 = Item2;
      Object.defineProperty(this, "Item1", {
          get: function() { return item1  }
      });
      Object.defineProperty(this, "Item2", {
          get: function() { return item2  }
      });
   }
   return Tuple;
})();

var tuple = new Tuple("Bob", 25); // Instantiation of a new Tuple
var name = tuple.Item1; // Assignment. name will be "Bob"
tuple.Item1 = "Kirk"; // Will not set it. It's immutable.

Ceci est un 2-tuple, cependant, vous pouvez modifier mon exemple pour prendre en charge les tuples 3,4,5,6 etc.

Faris Zacina
la source
En fait, ce n'est pas un t-uple mais une paire.
Pier Paolo Ramon
L' tupleinstance est toujours modifiable, donc ce n'est techniquement pas un tuple. Pour changer la preuve tuple.Item1 = "Steve"alors console.log()la sortie.
Evan Plaice
1
Merci d'avoir trouvé ça. J'ai modifié l'exemple pour rendre le Tuple immuable.
Faris Zacina
Comment modifiez-vous cela pour prendre en charge une longueur arbitraire?
aij
Cela ne répond pas à la question du PO, il a demandé une déstructuration
ThatWeirdo
0

Voici une version de la réponse de Matthew James Davis avec les méthodes de tuple Python ajoutées:

class Tuple extends Array { 
  constructor(...items) { 
    super(...items); 
    Object.freeze(this);
  }
  toArray() {
    return [...this];
  }
  toString() {
    return '('+super.toString()+')';
  }
  count(item) {
    var arr = this.toArray();
    var result = 0;
    for(var i = 0; i < arr.length; i++) {
       if(arr[i] === item) {
         result++;
       }
    }
    return result;
  }

  

  
}

   let tuple = new Tuple("Jim", 35);
   let [name,age] = tuple;

console.log("tuple:"+tuple)
console.log("name:"+name)
console.log("age:"+age)

Nirvana
la source