来自元组的JavaScript变量分配


101

在其他语言(例如Python 2和Python 3)中,您可以定义值并将其分配给元组变量,并按以下方式检索它们的值:

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

JavaScript中有类似的东西吗?还是我只需要用数组来做一个丑陋的事情:

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

有没有更好的方法在JavaScript 5中模拟Python元组?

更新:请参阅有关ES6的答案,对于新项目,应优先于CoffeeScript。


12
在JavaScript中,不要忘了声明变量:var tuple, name, age;
森那维达斯

3
var name=tuple[0], age=tuple[1]; 打字要多一些,但丑陋可能是夸大其词。
布伦特·布拉德本

Answers:


122

Javascript 1.7添加了非结构化赋值,它使您基本上可以完成之后的工作。

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

5
这不是基于标准的javascript,而是Mozilla特定的扩展。
ninjagecko 2012年

14
@ninjagecko:“ JavaScript”是Mozilla的实现,并且解构分配将成为即将到来的电子书标准的一部分
Bergi 2012年

65
实际上,它现在已成为ES6的一部分。
2014年

10
几年后,我的回答在技术上已经变得正确,但对正确和有用都无济于事。好极了!
pc1oad1etter

49

您必须以丑陋的方式来做。如果您确实想要这样的东西,可以查看CoffeeScript,它具有该功能以及许多其他功能,使其看起来更像python(对不起,听起来像是广告,但我真的很喜欢。)


嗯,这很有趣,我自己在这种情况下运行了,因为JavaScript似乎没有提供明显的元组支持,并且由于功能编程的紧张时期,您开发了对元组的需求。我也刚刚发现了这一点,但不确定是否可行,就元组支持而言,它看起来也不错: cs.umd.edu/projects/PL/arrowlets/api-tuples.xhtml。我一定会看一下CoffeeScript。
9codeMan9 2013年

29

您可以执行类似的操作:

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

然后将名称和年龄称为属性

tuple.name 
tuple.age 

5
我不会投票,但从技术上讲这是不正确的。声明对象后,您仍然可以更改(即更改)tuple.name和tuple.age的值。根据定义,不可变类型在定义后不能更改。它们就像只读类型,其中参数及其值只能声明一次。
Evan Plaice

4
@EvanPlaice如果可变性是一个问题,你可以使用Object.freeze(),即:tuple = Object.freeze({ name:'Bob', age:14 })
佳能

@canon我同意,这可能是整个线程中唯一可接受/正确的方法。不幸的是,mcm的答案不会冻结对象,因此它仍然是可变的。
Evan Plaice 2014年

@EvanPlaice我看不到可变性问题的来源-在原始的Python示例中元组不是可变的!
Daniel Buckmaster 2015年

@DanielBuckmaster Python中列表和元组之间的区别是,列表是可变的,而元组则不是。参见docs.python.org/2/tutorial/…。JavaScript本机不支持元组,因为除非创建后在对象上调用Object.freeze(),否则所有JS数据结构都是可变的。
埃文·普莱斯

27

此“元组”功能在EcmaScript2015中称为解构,不久将被最新的浏览器支持。目前,只有Firefox和Chrome支持它

但是,您可以使用转译器

该代码看起来像python一样好:

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

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

2
致未来读者:从chrome 49开始,Chrome支持此功能(根据Mozilla文档)。您还可以在此处使用Mozilla文档检查兼容性:developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/…–
Jamie

13

冻结数组的行为与python元组相同:

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

看中并定义一个类

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

今天可以在所有最新的浏览器中使用。


您不能将其设置为const吗?const是不可变的,不是吗?
标记A

3
不可以。const不可重新分配。你不能做const tuple = [“ Jim”,35]; 元组= [“ James”,35]。您可以执行const tuple = [“ Jim”,35]; tuple [0] =“詹姆斯”; 因此,它不是一成不变的。
马修·詹姆斯·戴维斯

6

JavaScript不支持元组

如果要查找不可变列表,则可以使用Object.freeze()使数组不可变。

Object.freeze()方法冻结一个对象:即,防止向其添加新属性;防止现有属性被删除;并防止更改现有属性或其可枚举性,可配置性或可写性。本质上,对象实际上是不可变的。该方法返回被冻结的对象。

资料来源:Mozilla开发人员网络-Object.freeze()

照常分配一个数组,但使用'Object.freeze()锁定它

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

像使用常规数组一样使用值(不支持python多重分配)

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

尝试分配新值

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

但是值不变

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

在旁注中,希望Tuples将在ES6中获得一流的支持。真正的本机元组(即异类序列)也将提高速度。
Evan Plaice 2015年

5

不幸的是,您不能在(ECMA | Java)Script中使用该元组分配语法。

编辑:有人链接到Mozilla / JS 1.7-这将无法跨浏览器工作,但是如果不需要这样做,那么您的答案就是了。


3

这并不是要在现实生活中实际使用,而只是一个有趣的练习。请参阅为什么使用JavaScript eval函数不是一个好主意?有关详细信息。

这是您无需借助特定于供应商的扩展即可获得的最接近的结果:

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

辅助功能:

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

证明它可以在任意范围内工作:

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

eval Safari不支持。


5
+1表示非常聪明,不过,切勿在现实生活中使用它:-p
Jamund Ferguson

3

作为部长回答的更新,您现在可以使用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,控制台


没有理由为什么您不能在ES2015之前做到这一点...这也没有回答OP的问题,他要求进行销毁
ThatWeirdo

3

您也可以在Javascript中使用元组类型。只需用更高阶的函数定义它(学术术语是教会编码):

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

请注意,Tuple它不用作常规构造函数。该解决方案完全不依赖原型系统,而仅依赖于高阶函数。

与元组(Array如元组)相比,元组有什么优势?教会编码的元组在设计上是不可变的,因此可以防止由突变引起的副作用。这有助于构建更强大的应用程序。另外,更容易推断出区分Arrays作为集合类型(例如[a])和元组作为各种类型的相关数据(例如(a, b))的代码的原因。


1

这是一个简单的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.

这是一个2元组,但是,您可以修改我的示例以支持3、4、5、6等元组。


实际上,这不是一对,而是一对。
保罗·拉蒙

tuple实例仍然可变,因此从技术上讲它不是元组。为了证明更改,tuple.Item1 = "Steve"然后console.log()输出。
Evan Plaice 2015年

1
感谢您的发现。我修改了示例,使元组不可变。
Faris Zacina 2015年

您如何修改它以支持任意长度?
2016年

这并没有回答OP的问题,他要求进行销毁
ThatWeirdo '16

0

这是Matthew James Davis的答案的版本,其中添加了Python元组方法:

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)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.