Cấu trúc hủy để lấy phần tử cuối cùng của một mảng trong es6


116

Trong coffeescript, điều này rất đơn giản:

coffee> a = ['a', 'b', 'program']
[ 'a', 'b', 'program' ]
coffee> [_..., b] = a
[ 'a', 'b', 'program' ]
coffee> b
'program'

Es6 có cho phép một cái gì đó tương tự không?

> 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)                                           

Tất nhiên tôi có thể làm theo cách của es5 -

const a = b[b.length - 1]

Nhưng có lẽ điều này hơi dễ bị sai sót bởi một lỗi. Có thể biểu tượng chỉ là thứ cuối cùng trong quá trình phá hủy?


7
Tại sao mọi người nghĩ ES6 thay đổi mọi thứ và có một số cú pháp mới để thực hiện xyz?
Felix Kling

23
@FelixKling câu hỏi đặc biệt là về hành vi của ...trong es6, đặc biệt là nó chỉ có thể được sử dụng làm thứ cuối cùng khi cấu trúc lại hoặc trong danh sách tham số. Điều này có khả năng phản trực giác đối với một người nào đó đi vào es6 từ coffeescript và do đó câu hỏi này có khả năng hữu ích.
George Simms

Điều đó có nghĩa là ngoài [1,2,3].slice(-1)bạn thậm chí không thể phá hủy tương đương với [1,2,3].slice(0, -1). Đây là những thao tác phổ biến. ES6 hủy cấu trúc bằng cách nào đó là một trò đùa!
scriptum

@ Ngay cả khi có một lý do chính đáng - để xử lý các tệp lặp vô hạn.
George Simms

Phần còn lại quá tệ vì tham số đầu tiên không hoạt động. Sẽ rất tuyệt ... Đây là câu nói jsperf sử dụng một số câu trả lời jsperf.com/destruct-last/1
Shanimal

Câu trả lời:


46

Không thể thực hiện được trong ES6 / 2015. Tiêu chuẩn không cung cấp cho nó.

Như bạn có thể thấy trong thông số kỹ thuật , FormalParameterListcó thể là:

  • a FunctionRestParameter
  • a FormalsList(danh sách các tham số)
  • a FormalsList, theo sau là aFunctionRestParameter

Sau khi FunctionRestParametertheo sau là thông số không được cung cấp.


215

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


4
Giải pháp đơn giản tốt đẹp không đột biến.
Jack Steam

1
@Shanimal Tùy thuộc, tôi đang tải popphiên bản nhanh hơn (OS X, Chrome 68).
Dave Newton

1
@ Dave Newton Nhưng pop () gây đột biến
Antonio Pantano

1
@AntonioPantano Có, nó làm thay đổi bản sao. Vấn đề là liệu nó có nhanh hơn hay không không phải là điều nhất định.
Dave Newton

53

Tôi tin rằng ES6 ít nhất có thể giúp được điều đó:

[...arr].pop()

Với mảng (arr) của bạn không phải là không xác định và một phần tử có thể lặp lại (vâng, các chuỗi thậm chí hoạt động !!), nó sẽ trả về phần tử cuối cùng .. ngay cả cho mảng trống và nó cũng không thay đổi nó. Nó tạo ra một mảng trung gian nhưng không tốn nhiều tiền.

Ví dụ của bạn sau đó sẽ giống như sau:

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


6
uhh, nó khá tệ, thậm chí .slice(-1)[0]là ít xấu hơn một chút, hoặc var [last]=arr.slice().reverse()là một cái xấu xí khác nếu bạn cần
caub

6
Tôi nghĩ bài đăng này là về ES6 / ES2015, phải không? Nhưng tôi đặc biệt thích tác phẩm cuối cùng của bạn. Làm thế nào về việc kết hợp cả hai var [last] = arr.slice(-1)
:;

13
cách yêu thích của tôi làObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
caub

3
Mặc dù điều này hoạt động nhưng nó có thể gây đột biến và xóa mục khỏi mảng ban đầu. Không lý tưởng trong nhiều trường hợp.
GavKilbride

4
@GavKilbride thì không. Ví dụ giống với ví dụ [].concat(arr).pop();không đột biến arr.
Dan

37

Bạn có thể hủy cấu trúc mảng đã đảo ngược để đến gần những gì bạn muốn.

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


2
Thông minh. Tốt hơn const last = ['bbb', 'uuu', 'iii'].slice(-1);? Về mặt biểu diễn?
Vadorequest

1
về .slice(-1)mặt kỹ thuật thì nhanh hơn, nhưng nó không cung cấp cho bạn cả mục cuối cùng VÀ mảng con trong một lần gọi, đây là một lợi ích của ...biểu tượng khi cơ cấu lại. Hiệu suất nhấn đảo ngược hai lần sẽ được xem xét khi sử dụng trên các mảng dài hơn, nhưng đối với một tập lệnh nhỏ có lẽ đáng để thuận tiện? Nhưng bạn có thể dễ dàng như let a = array.slice(-1), rest = array.slice(0,array.length-2)vậy nếu bạn vẫn muốn oneliner trong ES5, tức là nhanh hơn ~ 4%. jsperf.com/last-array-splat
mix3d

17

một cách tiếp cận khác là:

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


1
@isakbob yeap, bạn đây
Den Kerny,

khó đọc, hoặc có lẽ đó chỉ là bộ não của tôi
webjay

nó có thể rất hữu ích khi sử dụng nhiều đạo cụ, vì vậy, yea, nó chỉ là của bạn, xd xd xd
Den Kerny

5

Không nhất thiết phải là cách hoạt động hiệu quả nhất. Nhưng tùy thuộc vào ngữ cảnh, một cách khá thanh lịch sẽ là:

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

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


3
Tôi không thấy bất kỳ sự sang trọng nào trong giải pháp này, nhưng dù sao thì @shoesel cũng đã đăng nó rồi
Bergi

2

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

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

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


2
Có, tôi thấy nó hữu ích khi đã thực hiện cấu trúc lại khác. Bản thân nó không dễ đọc như giải pháp cổ điển.
andrhamm

1

Điều này sẽ hoạt động:

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

1

Bạn có thể thử hack này:

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

0

Chắc chắn, câu hỏi là về Hủy cấu trúc cho Mảng JavaScript và chúng tôi biết rằng không thể có mục cuối cùng của Mảng bằng cách sử dụng phép gán cấu trúc, có một cách để thực hiện nó là bất biến , hãy xem phần sau:

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 );

Chúng ta không arrthay đổi biến nhưng vẫn có tất cả các thành viên của mảng ngoại trừ mục cuối cùng là một mảng và có mục cuối cùng riêng biệt.



0

Không phá hủy cách nhưng có thể giúp đỡ. Theo tài liệu javascript và phương pháp đảo ngược có thể thử điều này:

const reversed = array1.reverse();
let last_item = reversed[0]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.