ทำลายโครงสร้างเพื่อรับองค์ประกอบสุดท้ายของอาร์เรย์ใน 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]

แต่บางทีนี่อาจจะเกิดข้อผิดพลาดเล็กน้อย Splat เป็นเพียงสิ่งสุดท้ายในการทำลายล้างได้หรือไม่?


7
ทำไมทุกคนถึงคิดว่า ES6 เปลี่ยนแปลงทุกอย่างและมีไวยากรณ์ใหม่สำหรับการทำ xyz?
Felix Kling

23
@FelixKling คำถามโดยเฉพาะอย่างยิ่งเกี่ยวกับพฤติกรรมของ...ใน es6 โดยเฉพาะอย่างยิ่งว่าสามารถใช้เป็นสิ่งสุดท้ายเมื่อทำลายโครงสร้างหรือในรายการพารามิเตอร์ สิ่งนี้อาจสวนทางกับคนที่เข้ามาใน es6 จาก coffeescript ดังนั้นคำถามนี้อาจมีประโยชน์
George Simms

นั่นหมายความว่านอกจากนี้คุณยังไม่สามารถเทียบเท่ากับ[1,2,3].slice(-1) destructure [1,2,3].slice(0, -1)สิ่งเหล่านี้เป็นการดำเนินการทั่วไป การทำลาย ES6 เป็นเรื่องตลก!
scriptum

@ แม้จะมีเหตุผลที่ถูกต้อง - เพื่อจัดการกับการวนซ้ำที่ไม่สิ้นสุด
George Simms

ส่วนที่เหลือแย่เกินไปเนื่องจากพารามิเตอร์แรกไม่ทำงาน คงจะเจ๋ง ... นี่คือ jsperf โดยใช้คำตอบบางส่วนjsperf.com/destructure-last/1
Shanimal

คำตอบ:


46

เป็นไปไม่ได้ใน ES6 / 2015 มาตรฐานไม่ได้ให้ไว้

ในขณะที่คุณสามารถมองเห็นในสเปคที่FormalParameterListสามารถเป็นได้ทั้ง:

  • FunctionRestParameter
  • a FormalsList(รายการพารามิเตอร์)
  • a FormalsListตามด้วยFunctionRestParameter

ไม่มีการ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)
Dave Newton

1
@Dave Newton But pop () ทำให้เกิดการกลายพันธุ์
Antonio Pantano

1
@AntonioPantano ใช่มันกลายพันธุ์สำเนา ประเด็นคือว่ามันเร็วกว่านั้นหรือไม่
Dave Newton

53

ฉันเชื่อว่าอย่างน้อย ES6 สามารถช่วยได้:

[...arr].pop()

เนื่องจากอาร์เรย์ (arr) ของคุณไม่ได้กำหนดไว้และเป็นองค์ประกอบที่ทำซ้ำได้ (ใช่แม้กระทั่งสตริงก็ใช้ได้ !!) มันควรส่งคืนองค์ประกอบสุดท้าย .. แม้จะเป็นอาร์เรย์ว่างเปล่าและก็ไม่ได้เปลี่ยนแปลงด้วยเช่นกัน มันสร้างอาร์เรย์กลางแม้ว่า.. แต่ไม่ควรเสียค่าใช้จ่ายมาก

จากนั้นตัวอย่างของคุณจะมีลักษณะดังนี้:

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


6
เอ่อมันค่อนข้างแย่แม้.slice(-1)[0]จะแย่น้อยกว่าหรือvar [last]=arr.slice().reverse()เป็นอีกอันที่น่าเกลียดถ้าคุณต้องการ
caub

6
ฉันคิดว่าโพสต์นี้เกี่ยวกับ ES6 / ES2015 ไม่ใช่เหรอ? แต่ฉันชอบชิ้นสุดท้ายของคุณเป็นพิเศษ วิธีการรวมทั้งสอง: var [last] = arr.slice(-1);)
shoesel

13
วิธีที่ฉันชอบคือObject.defineProperty(Array.prototype, -1, { get() {return this[this.length - 1] } }); [1,2,3][-1]
caub

3
แม้ว่าวิธีนี้จะใช้งานได้ แต่ก็เป็นการกลายพันธุ์และลบรายการออกจากอาร์เรย์เดิม ไม่เหมาะในหลาย ๆ สถานการณ์
GavKilbride

4
@GavKilbride มันไม่ได้ ตัวอย่างเป็นเช่นเดียวกับที่ไม่กลายพันธุ์[].concat(arr).pop(); arr
แดน

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)เป็นเทคนิคที่เร็วขึ้น แต่จะไม่ให้คุณทั้งสองรายการสุดท้ายและ subarray ในหนึ่งสายซึ่งเป็นประโยชน์ในการเป็น...เครื่องหมายเมื่อ destructuring ประสิทธิภาพของการย้อนกลับสองครั้งจะถูกนำมาพิจารณาเมื่อใช้กับอาร์เรย์ที่ยาวขึ้น แต่สำหรับสคริปต์ขนาดเล็กอาจคุ้มค่ากับความสะดวก? แต่คุณสามารถทำได้ง่าย ๆ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 เย้คุณอยู่ที่นี่
Den Kerny

อ่านยากหรืออาจเป็นแค่สมองของฉัน
webjay

มันอาจจะมีประโยชน์มากในการใช้อุปกรณ์ประกอบฉากหลายชิ้นใช่มันเป็นของคุณเท่านั้น xd xd xd
Den Kerny

6

ไม่จำเป็นต้องเป็นวิธีที่มีประสิทธิภาพมากที่สุด แต่ขึ้นอยู่กับบริบทวิธีที่ค่อนข้างหรูหราจะเป็น:

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

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


3
ฉันไม่เห็นความสง่างามใด ๆ ในโซลูชันนี้ แต่อย่างไรก็ตาม @shoesel ได้โพสต์ไว้แล้ว
Bergi

2

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

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

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


2
ใช่ฉันคิดว่ามันมีประโยชน์เมื่อทำการทำลายล้างอื่น ๆ แล้ว ด้วยตัวมันเองมันไม่ง่ายที่จะอ่านเหมือนกับวิธีแก้ปัญหาแบบคลาสสิก
andrhamm



1

ไม่ใช่วิธีทำลายล้าง แต่สามารถช่วยได้ ตามเอกสาร javascript และวิธีการย้อนกลับสามารถลองสิ่งนี้:

const reversed = array1.reverse();
let last_item = reversed[0]

0

แน่นอนว่าคำถามเกี่ยวกับDestructuringสำหรับ JavaScript Arrays และเราทราบดีว่าเป็นไปไม่ได้ที่จะมีรายการสุดท้ายของ Array โดยใช้การมอบหมายการทำลายมีวิธีที่จะทำให้ไม่เปลี่ยนรูปดูดังต่อไปนี้:

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ตัวแปร แต่ยังคงมีสมาชิกอาร์เรย์ทั้งหมดยกเว้นรายการสุดท้ายเป็นอาร์เรย์และมีรายการสุดท้ายแยกกัน


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.