Руйнування для отримання останнього елемента масиву в es6


116

У кофескрипті це прямо:

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]

Але, можливо, це трохи схильне однією помилкою. Чи може бризка бути лише останньою справою у руйнуванні?


7
Чому всі думають, що ES6 все змінює, і є новий синтаксис для xyz?
Фелікс Клінг

23
@FelixKling питання стосується, зокрема, поведінки ...в es6, особливо те, що його можна використовувати лише як останнє при руйнуванні або в списку параметрів. Це може бути протиінтуїтивним для того, хто потрапляє в es6 з coffeescript, і тому це питання може бути корисним.
Джордж Сіммс

Це означає, що крім [1,2,3].slice(-1)вас навіть не вдається зруйнувати рівноцінне [1,2,3].slice(0, -1). Це звичайні операції. Руйнування ES6 - це якось жарт!
scriptum

@Якщо є законна причина - обробляти нескінченні ітерабелі.
Джордж Сіммс

Занадто поганий відпочинок, оскільки перший параметр не працює. Було б круто ... Ось jsperf, використовуючи деякі відповіді jsperf.com/destructure-last/1
Shanimal

Відповіді:


46

Це неможливо в ES6 / 2015. Стандарт просто не передбачає цього.

Як ви бачите у специфікації , це FormalParameterListможе бути:

  • а FunctionRestParameter
  • a FormalsList(список параметрів)
  • a FormalsList, а за ним aFunctionRestParameter

Після FunctionRestParameterнаступних параметрів не передбачений.


215

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


4
Приємне просте немутаційне рішення.
Jack Steam

1
@Shanimal Залежить, я отримую popверсію якнайшвидше (OS X, Chrome 68).
Дейв Ньютон

1
@Dave Newton But pop () викликає мутацію
Антоніо Пантано

1
@AntonioPantano Так, копія вимкнено. Справа в тому, швидше це чи ні, не дається.
Дейв Ньютон

53

Я вважаю, що ES6 міг би принаймні допомогти у цьому:

[...arr].pop()

З огляду на те, що масив (arr) не визначений, а ітерабельний елемент (так, навіть рядки працюють !!), він повинен повернути останній елемент. Навіть для порожнього масиву, і він також не змінює його. Він створює проміжний масив, хоча ... але це не повинно дорого коштувати.

Тоді ваш приклад виглядатиме так:

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


6
е-е, це зовсім погано, навіть .slice(-1)[0]трохи менше погано, або var [last]=arr.slice().reverse()це ще одне потворне, якщо вам потрібно
кают

6
Я думав, це повідомлення про ES6 / ES2015, ні? Але мені подобається особливо твій останній твір. Як щодо поєднання двох var [last] = arr.slice(-1)
:;

13
мій улюблений спосібObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
кабіна

3
Хоча це працює, він є мутаційним і видаляє елемент з початкового масиву. Не ідеально для багатьох сценаріїв.
GavKilbride

4
@GavKilbride це не так. Приклад такий самий, [].concat(arr).pop();який не мутує arr.
Dan

37

Ви можете деструктурувати перевернутий масив, щоб наблизитись до того, що ви хочете.

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


2
Розумний. Краще, ніж const last = ['bbb', 'uuu', 'iii'].slice(-1);? З точки зору виступів?
Vadorequest

1
то .slice(-1)технічно швидше, але це не дає вам як останній елемент , і подмассів в одному виклику, який є перевагою ...знаку оклику , коли знищення того . Ударність продуктивності реверсування двічі має враховуватися при використанні на довших масивах, але для невеликого сценарію, мабуть, варто зручності? Але ви могли б так само легко, let a = array.slice(-1), rest = array.slice(0,array.length-2)якби все-таки хотіли oneliner в ES5, тобто на 4% швидше. jsperf.com/last-array-splat
mix3d

17

інший підхід:

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


1
@isakbob yeap, ось ти
Den Kerny

важко читати, а може це просто мій мозок
webjay

це може бути дуже корисно за допомогою декількох реквізитів, так що так, це тільки ваше, xd xd xd
Den Kerny

5

Не обов'язково найефективніший спосіб виконання. Але залежно від контексту досить елегантним буде:

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

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


3
Я не бачу елегантності в цьому рішенні, але все одно @shoesel вже розмістив його
Бергі

2

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

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

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


2
Так, я вважаю це корисним, коли вже роблю інші руйнування. Само по собі це не так просто прочитати, як класичне рішення.
andrhamm


1

Ви можете спробувати цей злом:

let a = ['a', 'b', 'program'];
let [last] = a.reverse();
a.reverse();
console.log(last);

0

Безумовно, питання стосується деструктуризації для масивів JavaScript, і ми знаємо, що не можна мати останній елемент масиву, використовуючи завдання деструктування, є спосіб зробити це непорушним , див. Наступне:

const arr = ['a', 'b', 'c', 'last'];

~~~
const arrDepth = arr.length - 1;

const allExceptTheLast = arr.filter( (dep, index) => index !== arrDepth && dep );
const [ theLastItem ] = arr.filter( (dep, index) => index === arrDepth && dep );

Ми не мутуємо arrзмінну, але все ж маємо всі члени масиву, крім останнього елемента, як масив, а останній елемент є окремо.



0

Не руйнує шлях, але може допомогти. Відповідно до документації javascript та зворотного методу можна спробувати це:

const reversed = array1.reverse();
let last_item = reversed[0]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.