Assegnazioni di variabili JavaScript da tuple


99

In altri linguaggi come Python 2 e Python 3, puoi definire e assegnare valori a una variabile tupla e recuperarne i valori in questo modo:

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

C'è qualcosa di simile in JavaScript? O devo solo farlo nel modo brutto con un array:

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

C'è un modo migliore per simulare le tuple Python in JavaScript 5?

Aggiornamento: vedere la risposta relativa a ES6, che dovrebbe essere preferito a CoffeeScript per i nuovi progetti.


12
In JavaScript, non dimenticare di dichiarare le variabili:var tuple, name, age;
Šime Vidas

3
var name=tuple[0], age=tuple[1]; È un po 'più di digitazione, ma brutto potrebbe essere un'esagerazione.
Brent Bradburn

Risposte:


120

Javascript 1.7 ha aggiunto l' assegnazione destrutturata che ti consente di fare essenzialmente quello che stai cercando.

function getTuple(){
   return ["Bob", 24];
}
var [a, b] = getTuple();
// a === "bob" , b === 24 are both true

5
Questo non è un javascript basato su standard, ma piuttosto estensioni specifiche di Mozilla.
ninjagecko

14
@ninjagecko: "JavaScript" è l'implementazione di Mozilla e le assegnazioni di destrutturazione faranno parte del prossimo standard ecmascript
Bergi

64
Ora è infatti parte di ES6.
Pier Paolo Ramon

9
In pochi anni la mia risposta è diventata tecnicamente corretta ma non utile né corretta né utile. Sìì!
pc1oad1etter

49

Devi farlo nel modo brutto. Se vuoi davvero qualcosa di simile, puoi dare un'occhiata a CoffeeScript , che ha questo e molte altre caratteristiche che lo fanno sembrare più simile a Python (scusami per averlo fatto sembrare una pubblicità, ma mi piace molto.)


Hmm, questo è piuttosto interessante, mi sono appena imbattuto in questo scenario da solo, poiché JavaScript non sembra fornire un ovvio supporto per le tuple e, provenendo da un intenso periodo di programmazione funzionale, sviluppi la voglia di tuple. Ho anche appena trovato questo, ma non sono sicuro che funzioni, sembrava buono anche in termini di supporto per le tuple: cs.umd.edu/projects/PL/arrowlets/api-tuples.xhtml . Sicuramente guarderò CoffeeScript.
9codeMan9

29

Puoi fare qualcosa di simile:

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

e quindi fare riferimento a nome ed età come attributi

tuple.name 
tuple.age 

5
Non downvote ma tecnicamente questo non è corretto. È ancora possibile modificare (cioè mutare) i valori di tuple.name e tuple.age dopo che l'oggetto è stato dichiarato. Per definizione, i tipi immutabili non possono essere modificati dopo essere stati definiti. Sono come tipi di sola lettura in cui sia i parametri che i relativi valori possono essere dichiarati solo una volta.
Evan Plaice

4
@EvanPlaice se la mutabilità è un problema, potresti usare Object.freeze(), ad esempio:tuple = Object.freeze({ name:'Bob', age:14 })
canone

@canon Sono d'accordo, questo è probabilmente l'unico approccio accettabile / corretto in tutta questa discussione. Sfortunatamente, la risposta di mcm non congela l'oggetto, quindi è ancora modificabile.
Evan Plaice

@EvanPlaice Non vedo da dove provenga il problema della mutabilità: le tuple non sono immutabili nell'esempio originale di Python!
Daniel Buckmaster

@DanielBuckmaster La differenza tra una lista e una tupla in Python è che una lista è mutabile mentre una tupla non lo è. Vedi docs.python.org/2/tutorial/… . Le tuple non sono supportate in modo nativo in JavaScript perché tutte le strutture dati JS sono modificabili a meno che non si chiami Object.freeze () sull'oggetto dopo la creazione.
Evan Plaice

27

Questa caratteristica "tupla" si chiama destrutturazione in EcmaScript2015 e presto sarà supportata dai browser aggiornati. Per il momento, solo Firefox e Chrome lo supportano .

Ma hey, puoi usare un transpiler .

Il codice sarebbe bello come Python:

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

console.log(name)
console.log(age)

2
Per i futuri lettori: questa funzione è supportata in Chrome da Chrome 49 (secondo i documenti di Mozilla). Puoi anche verificare la compatibilità utilizzando i documenti di Mozilla qui: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
Jamie

12

Un array congelato si comporta in modo identico a una tupla python:

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

Sii fantasioso e definisci una 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

Funziona oggi in tutti i browser più recenti.


Non potresti semplicemente impostarlo su un const? La const è immutabile, no?
Mark A

2
No. La const non è riassegnabile. Non puoi eseguire const tuple = ["Jim", 35]; tuple = ["James", 35]. Puoi eseguire const tuple = ["Jim", 35]; tuple [0] = "James"; Quindi non è immutabile.
Matthew James Davis

6

Le tuple non sono supportate in JavaScript

Se stai cercando un elenco immutabile, Object.freeze () può essere utilizzato per rendere immutabile un array.

Il metodo Object.freeze () congela un oggetto: cioè, impedisce l'aggiunta di nuove proprietà; impedisce la rimozione delle proprietà esistenti; e impedisce la modifica delle proprietà esistenti o della loro enumerabilità, configurabilità o scrivibilità. In sostanza l'oggetto è reso effettivamente immutabile. Il metodo restituisce l'oggetto congelato.

Fonte: Mozilla Developer Network - Object.freeze ()

Assegna un array come al solito ma bloccalo usando 'Object.freeze ()

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

Usa i valori come faresti con un normale array (l'assegnazione multipla di Python non è supportata)

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

Tenta di assegnare un nuovo valore

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

Ma il valore non viene modificato

> console.log(tuple)
[ 'Bob', 24 ]

In una nota a margine si spera che Tuples ottenga un supporto di prima classe in ES6. Anche la vera tupla nativa (cioè la sequenza eterogenea) migliorerà la velocità.
Evan Plaice

5

Sfortunatamente non puoi usare quella sintassi di assegnazione delle tuple nello script (ECMA | Java).

EDIT: Qualcuno collegato a Mozilla / JS 1.7 - questo non funzionerebbe cross-browser, ma se ciò non è richiesto, c'è la tua risposta.


3

Questo non è inteso per essere effettivamente utilizzato nella vita reale, ma solo un esercizio interessante. Vedi Perché usare la funzione di valutazione JavaScript è una cattiva idea?per dettagli.

Questo è il massimo che puoi ottenere senza ricorrere a estensioni specifiche del fornitore:

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

Funzione di aiuto:

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(',');
}

Prova che funziona in ambito arbitrario:

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

eval non è supportato in Safari.


5
+1 per essere super intelligente, non usarlo mai nella vita reale però :-p
Jamund Ferguson

3

Come aggiornamento alla risposta del ministro, ora puoi farlo con 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


Non c'è motivo per cui non potresti farlo prima di ES2015 ... Anche questo non risponde alla domanda dell'OP, ha chiesto la destrutturazione
ThatWeirdo

3

Puoi anche avere un tipo di tupla in Javascript. Basta definirlo con funzioni di ordine superiore (il termine accademico è codifica Church):

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

Si noti che Tuplenon viene utilizzato come un normale costruttore. La soluzione non si basa affatto sul sistema prototipo, ma esclusivamente su funzioni di ordine superiore.

Quali sono i vantaggi delle tuple rispetto a quelle Arrayusate come le tuple? Le tuple con codice Church sono immutabili per impostazione predefinita e quindi prevengono gli effetti collaterali causati dalle mutazioni. Questo aiuta a creare applicazioni più robuste. Inoltre, è più facile ragionare sul codice che distingue tra Arrays come tipo di raccolta (ad esempio [a]) e tuple come dati correlati di vario tipo (ad esempio (a, b)).


1

Ecco una semplice implementazione della tupla Javascript:

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.

Questa è una tupla a 2, tuttavia, potresti modificare il mio esempio per supportare le tuple 3,4,5,6 ecc.


In realtà questo non è un t-uple ma una coppia.
Pier Paolo Ramon

L' tupleistanza è ancora modificabile, quindi tecnicamente non è una tupla. Per la modifica della prova, tuple.Item1 = "Steve"quindi console.log()l'output.
Evan Plaice

1
Grazie per averlo trovato. Ho modificato l'esempio per rendere immutabile la tupla.
Faris Zacina

Come lo modifichi per supportare una lunghezza arbitraria?
aij

Questo non risponde alla domanda dell'OP, ha chiesto la destrutturazione
ThatWeirdo

0

Ecco una versione della risposta di Matthew James Davis con i metodi della tupla Python aggiunti in:

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)

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.