In other languages like Python 2 and Python 3, you can define and assign values to a tuple variable, and retrieve their values like this:

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

Is there anything similar in JavaScript? Or do I just have to do it the ugly way with an array:

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

Is there a better way to simulate Python tuples in JavaScript 5?

Update: See the answer regarding ES6, which should be favored over CoffeeScript for new projects.

2

12 Answers

Javascript 1.7 added destructuring assignment which allows you to do essentially what you are after.

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

You have to do it the ugly way. If you really want something like this, you can check out CoffeeScript, which has that and a whole lot of other features that make it look more like python (sorry for making it sound like an advertisement, but I really like it.)

2

You can do something similar:

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

and then refer to name and age as attributes

tuple.name tuple.age 
11

This "tuple" feature it is called destructuring in EcmaScript2015 and is soon to be supported by up to date browsers. For the time being, only Firefox and Chrome support it.

But hey, you can use a transpiler.

The code would look as nice as python:

let tuple = ["Bob", 24] let [name, age] = tuple console.log(name) console.log(age) 
1

A frozen array behaves identically to a python tuple:

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

Be fancy and define a class

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 

Works today in all the latest browsers.

2

Tuples aren't supported in JavaScript

If you're looking for an immutable list, Object.freeze() can be used to make an array immutable.

The Object.freeze() method freezes an object: that is, prevents new properties from being added to it; prevents existing properties from being removed; and prevents existing properties, or their enumerability, configurability, or writability, from being changed. In essence the object is made effectively immutable. The method returns the object being frozen.

Source: Mozilla Developer Network - Object.freeze()

Assign an array as usual but lock it using 'Object.freeze()

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

Use the values as you would a regular array (python multi-assignment is not supported)

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

Attempt to assign a new value

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

But the value is not changed

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

Unfortunately you can't use that tuple assignment syntax in (ECMA|Java)Script.

EDIT: Someone linked to Mozilla/JS 1.7 - this wouldn't work cross-browser but if that is not required then there's your answer.

This is not intended to be actually used in real life, just an interesting exercise. See Why is using the JavaScript eval function a bad idea? for details.

This is the closest you can get without resorting to vendor-specific extensions:

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

Helper function:

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

Proof that it works in arbitrary scope:

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

eval is not supported in Safari.

1

As an update to The Minister's answer, you can now do this with 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" 

1

You can have a tuple type in Javascript as well. Just define it with higher order functions (the academic term is Church encoding):

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

Please note that Tuple isn't used as a normal constructor. The solution doesn't rely on the prototype system at all, but solely on higher order functions.

What are the advantages of tuples over Arrays used like tuples? Church encoded tuples are immutable by design and thus prevent side effects caused by mutations. This helps to build more robust applications. Additionally, it is easier to reason about code that distinguishes between Arrays as a collection type (e.g. [a]) and tuples as related data of various types (e.g. (a, b)).

Here is a simple Javascript Tuple implementation:

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. 

This is a 2-tuple, however, you could modify my example to support 3,4,5,6 etc. tuples.

8

I made a tuple implementation that works quite well. This solution allows for array destructuring, as well as basic type-cheking.

const Tuple = (function() { function Tuple() { // Tuple needs at least one element if (arguments.length < 1) { throw new Error('Tuple needs at least one element'); } const args = { ...arguments }; // Define a length property (equal to the number of arguments provided) Object.defineProperty(this, 'length', { value: arguments.length, writable: false }); // Assign values to enumerable properties for (let i in args) { Object.defineProperty(this, i, { enumerable: true, get() { return args[+i]; }, // Checking if the type of the provided value matches that of the existing value set(value) { if (typeof value !== typeof args[+i]) { throw new Error('Cannot assign ' + typeof value + ' on ' + typeof args[+i]); } args[+i] = value; } }); } // Implementing iteration with Symbol.iterator (allows for array destructuring as well for...of loops) this[Symbol.iterator] = function() { const tuple = this; return { current: 0, last: tuple.length - 1, next() { if (this.current <= this.last) { let val = { done: false, value: tuple[this.current] }; this.current++; return val; } else { return { done: true }; } } }; }; // Sealing the object to make sure no more values can be added to tuple Object.seal(this); } // check if provided object is a tuple Tuple.isTuple = function(obj) { return obj instanceof Tuple; }; // Misc. for making the tuple more readable when printing to the console Tuple.prototype.toString = function() { const copyThis = { ...this }; const values = Object.values(copyThis); return `(${values.join(', ')})`; }; // conctat two instances of Tuple Tuple.concat = function(obj1, obj2) { if (!Tuple.isTuple(obj1) || !Tuple.isTuple(obj2)) { throw new Error('Cannot concat Tuple with ' + typeof (obj1 || obj2)); } const obj1Copy = { ...obj1 }; const obj2Copy = { ...obj2 }; const obj1Items = Object.values(obj1Copy); const obj2Items = Object.values(obj2Copy); return new Tuple(...obj1Items, ...obj2Items); }; return Tuple; })(); const SNAKE_COLOR = new Tuple(0, 220, 10); const [red, green, blue] = SNAKE_COLOR; console.log(green); // => 220 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy