在ES6中,可以使用解构赋值来获取数组的最后一个元素。

168
CoffeeScript中,这很简单:
coffee> a = ['a', 'b', 'program']
[ 'a', 'b', 'program' ]
coffee> [_..., b] = a
[ 'a', 'b', 'program' ]
coffee> b
'program'

ES6允许类似的功能吗?
> const [, b] = [1, 2, 3]
'use strict'
> b  // it got the second element, not the last one!
2
> const [...butLast, last] = [1, 2, 3]
SyntaxError: repl: Unexpected token (1:17)
> 1 | const [...butLast, last] = [1, 2, 3]
    |                  ^
    at Parser.pp.raise (C:\Users\user\AppData\Roaming\npm\node_modules\babel\node_modules\babel-core\node_modules\babylon\lib\parser\location.js:24:13)

当然,我可以用ES5的方式来做。
const a = b[b.length - 1]

但也许这样容易出现一点偏差。展开运算符只能在解构中的最后一个位置吗?

36
@FelixKling 这个问题特别关注在es6中...的行为,尤其是它只能在解构或参数列表中作为最后一项使用。对于从Coffeescript转入es6的人来说,这可能会产生反直觉的感觉,因此这个问题有潜在的用处。 - George Simms
1
这意味着除了 [1,2,3].slice(-1) 之外,你甚至不能解构等同于 [1,2,3].slice(0, -1) 的操作。这些是常见的操作。ES6 解构有点像一个笑话! - user5536315
@Iven 有一个合理的原因 - 处理无限可迭代对象。 - George Simms
很遗憾,将rest参数作为第一个参数不起作用。本来会很酷的...... 这里有一个使用一些答案的jsperf https://jsperf.com/destructure-last/1 - Shanimal
2
有一个名为“双向迭代器和解构”的TC39提案,它与这个问题相关联。 - Sebastian Simon
const [c] = ['bee'].slice(-1)有什么问题吗? - Andre Figueiredo
19个回答

265

console.log('last', [1, 3, 4, 5].slice(-1));
console.log('second_to_last', [1, 3, 4, 5].slice(-2));


11
不错的简单非交换解决方案。 - Jack Steam
2
@Shanimal 这取决于你的情况,我发现pop版本更快(在OS X和Chrome 68上)。 - Dave Newton
3
@Dave Newton,但是pop()会导致变异。 - Antonio Pantano
1
@AntonioPantano 是的,它会改变副本。关键是它是否更快并不确定。 - Dave Newton
3
若要返回值为'program'而非['program'],请使用['a','b','program'].slice(-1)[0]。对于空数组,这将返回undefined - oriadam
显示剩余2条评论

73

我相信ES6至少可以帮助解决这个问题:

[...arr].pop()

给定你的数组(arr)不是未定义的并且是可迭代的元素(甚至字符串也可以工作!!),它应该返回最后一个元素,即使对于空数组也是如此,而且它也不会改变它。它虽然会创建一个中间数组..但那不应该花费太多。
您的示例将如下所示:

  console.log(  [...['a', 'b', 'program']].pop() );


8
嗯,这很糟糕,即使使用.slice(-1)[0]也略微好一些,或者如果需要的话,var [last]=arr.slice().reverse()另一种丑陋的方法。 - caub
10
我觉得这篇文章是关于ES6/ES2015的,不是吗?但我特别喜欢你的最后一段。把两个内容结合起来怎么样:var [last] = arr.slice(-1) ;) - shoesel
14
我最喜欢的方法是 Object.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1] - caub
4
尽管这个方法能够起作用,但它会改变原数组并删除其中的元素。在许多情况下并不理想。 - GavKilbride
6
它并没有。举个例子,它与[].concat(arr).pop();相同,不会改变arr - Dan
显示剩余5条评论

61
您可以解构反转后的数组以接近您想要的结果。

const [a, ...rest] = ['a', 'b', 'program'].reverse();
  
document.body.innerHTML = 
    "<pre>"
    + "a: " + JSON.stringify(a) + "\n\n"
    + "rest: " + JSON.stringify(rest.reverse())
    + "</pre>";


3
在性能方面,智能型比const last = ['bbb', 'uuu', 'iii'].slice(-1);更出色吗? - Vadorequest
3
.slice(-1) 在技术上更快,但它不能在一次调用中同时返回最后一个元素和子数组,这也是解构时使用 ... 扩展运算符的好处。在处理较长的数组时,需要考虑两次反转的性能损失,但对于小脚本来说,方便性可能更值得。但如果你仍然想要 ES5 中的单行代码,你也可以像这样写:let a = array.slice(-1), rest = array.slice(0,array.length-2),它将会比扩展运算符快约 4%。https://jsperf.com/last-array-splat - mix3d
这很聪明 :D - ncubica
2
这种解决方案仍然会改变原始数组,这在实际情况下并不理想。 - Mg Gm

61

在ES6/2015中是不可能的。标准并没有对其进行规定。

正如您可以在规范中看到,FormalParameterList可以是以下之一:

  • FunctionRestParameter
  • FormalsList(参数列表)
  • FormalsList,后跟一个FunctionRestParameter

规范中没有提供让FunctionRestParameter跟随其他参数的方法。


44
另一种方法是:

const arr = [1, 2, 3, 4, 5]
const { length, [length - 1]: last } = arr; // Should be 5
console.log(last)


你不必捕获 length...rest 更有用。 - Константин Ван
@КонстантинВан 是的,这很常见,我的却很罕见,但确实非常有用。 - Den Kerny
这是一个宝石 @DenKerny! - Rafid Muhymin Wafi

9
你可以尝试使用应用于数组的对象解构来提取length并获取最后一个项目,例如:

解构赋值

const { length, 0: first, [length - 1]: last } = ['a', 'b', 'c', 'd']

// length = 4
// first = 'a'
// last = 'd'

更新

另一种方法是使用Array.prototype.at()

at() 方法接受一个整数值并返回该索引处的项,允许使用正整数和负整数...

const last = ['a', 'b', 'c', 'd'].at(-1)
// 'd'

1
我真的认为这是目前(2022年中)最好的方法。非常感谢! - Amir Arad
at()更方便,因为它返回元素,而slice()返回一个数组。 - undefined

8

不一定是最高效的方法。但根据上下文,一种相当优雅的方法是:

const myArray = ['one', 'two', 'three'];
const theOneIWant = [...myArray].pop();

console.log(theOneIWant); // 'three'
console.log(myArray.length); //3


5
我并没有看到这个解决方案中的任何优雅之处,但无论如何@shoesel已经发布了它。 - Bergi
1
个人口味不同 ;) 我喜欢它 - Sebastian Schürmann
它以何种方式优雅? - undefined
好的,OP已经“离开了大楼”:“最后一次出现是在6年前” - undefined

8

获取数组的最后一个元素:

const [last,] = ['a', 'b', 'program'].reverse();

1
我必须补充说明的是,JavaScript 数组反转是原地进行的。因此,这个解决方案可能不适合每个人,并且/或者存在性能问题。我曾经吃过亏... - Shane Hsu
基本上与此解决方案相同。它仍然存在相同的问题,即改变数组的值。 - VLAZ

5

const arr = ['a', 'b', 'c']; // => [ 'a', 'b', 'c' ]

const {
  [arr.length - 1]: last
} = arr;

console.log(last); // => 'c'


3
在进行其他解构操作时,我发现这个方法很有用。但单独使用时,它不如经典解决方案易读。 - andrhamm

5

这应该能够工作:

const [lastone] = myArray.slice(-1);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接