获取数组中的最后一项

2064

这是我目前的JavaScript代码:

var linkElement = document.getElementById("BackButton");
var loc_array = document.location.href.split('/');
var newT = document.createTextNode(unescape(capWords(loc_array[loc_array.length-2]))); 
linkElement.appendChild(newT);

目前从URL中获取数组的倒数第二个项目。但是,我想检查最后一个项目是否为"index.html",如果是,则获取倒数第三个项目。

63个回答

2393
if (loc_array[loc_array.length - 1] === 'index.html') {
   // do something
} else {
   // something else
}

如果你的服务器对于 "index.html" 和 "inDEX.htML" 提供了相同的文件,你也可以使用 .toLowerCase()

然而,如果可能的话,你可能想考虑在服务器端完成这个操作:这样做会更加干净,并且对于没有 JS 的人也能起作用。


编辑 - ES-2022

使用 ES-2022 Array.at(),以上内容可以这样写:

if (loc_array.at(-1) === 'index.html') {
   // do something
} else {
   // something else
}

85
如果你只需要最后一个元素,可以使用 Array.pop()。 - Badri Derakhshan
110
这样做必然会在返回数组之前删除最后一个元素,所以如果你只想检查数组的最后一个元素,这不是一个选项。你还需要将它推回去,才能恢复数组到原来的状态。 - Robidu
27
@BadriDerakhshan的解决方案适用于创建临时数组的情况。例如,可以将x = string.split('/'); return x[x.length-1]替换为return x.split('/').pop()。请注意,这不会改变原来的意思,我已经尽力使翻译通俗易懂。 - Harry
5
不适用于Safari。 - Carlos Souza
20
at()方法在 Safari IOS、Chrome IOS 和 Samsung Internet 中不受支持。 https://caniuse.com/mdn-javascript_builtins_string_at - Alex Grogan
显示剩余6条评论

1617

不确定是否有缺点,但这似乎是相当简明的:

arr.slice(-1)[0] 
或者
arr.slice(-1).pop()

如果数组为空,两者都会返回undefined


196
使用解构语法也很好:const [lastItem] = arr.slice(-1) - diachedelic
93
slice() 方法会新建一个数组并复制单个元素,而 pop() 只修改该副本。原始数组将保持不变。 - kritzikratzi
但是,除非不经常调用此代码,否则应避免创建新数组。否则,它将对垃圾收集造成额外的负担,并且/或者会使浏览器使用更多内存。 - mvmn
8
@mvmn 我很久以前做过基准测试,吞吐量大约是每秒一到两百万个调用在单个2.4GHz线程上。所以除非你解决了在JS中本来就不应该解决的问题,否则它不会有什么显著的影响(如果我没记错,与arr[arr.length-1]相比的减速比为50-100倍)。 - kritzikratzi
7
这种方法非常缓慢。 - Govan
15
@Govan 请查看我的评论。你可以称这为每秒过高的次数。如果需要更多,或者数组长度已知,请使用普通的数组访问以获得最大的性能 arr[arr.length-1] - kritzikratzi

422

使用Array.pop方法:

var lastItem = anArray.pop();

重要提示:此方法返回数组的最后一个元素,并从数组中删除它。


13
特别适合这样的用法:filename.split('.').pop() - armin.miedl
32
它不仅返回最后一个元素,而且会将其删除! - slim
5
const lastItem = [...anArray].pop()是避免更改原数组的方法。 - Norfeldt

218

@chaiguy所发表的简短版本:

Array.prototype.last = function() {
    return this[this.length - 1];
}

读取-1索引已经返回undefined

编辑:

现在的偏好似乎是使用模块并避免操作原型或使用全局命名空间。

export function last(array) {
    return array[array.length - 1];
}

11
如果不清楚如何实际使用,请看下面的示例:var lastItem = [3,2,1,5].last();lastItem 的值为 5 - user5670895
16
这个答案正确而且表述清晰,但是(!!!)在使用Javascript时有一个经验法则:不要修改你没有所有权的对象。这样做很危险,因为有很多原因。例如,1. 在你的团队中工作的其他开发人员可能会感到困惑,因为这种方法并不标准。2. 任何库的更新,甚至使用更低或更高版本的ECMAScript都可能导致它容易丢失! - Farzad Yousefzadeh
2
对于任何想知道的人,这会破坏Array.forEach()。我仍然同意修改原型不是最糟糕的事情,但这个确实很糟糕。 - Seph Reed
5
我认为修改Array.prototype并不是一个大问题,但你应该使用 Object.assign(Array.prototype, 'last', { value: function () { … } });。否则该属性将是可枚举的。 - 黄雨伞
如果你要扩展内置原型或填充属性(即猴子补丁),请确保正确性:为了向前兼容,请先检查属性是否存在,然后使属性不可枚举,以便构造对象的自有键不会被污染。对于方法,请使用_实际的_方法。我的建议是:遵循这些示例,演示如何添加一个行为与其他内置方法尽可能相似的方法。 - Sebastian Simon
显示剩余4条评论

202

感谢提供 jsperf 链接。从性能角度来看,第二个选项是无意义的。 - Leos Literak
19
第一个选项非常明显,它的作用很清楚。第二个选项则不那么明显。 - isset

150

表现

2020.05.16 我在 MacOs High Sierra v10.13.6 上使用 Chrome v81.0,Safari v13.1 和 Firefox v76.0 进行了选定解决方案的测试。

结论

  • arr[arr.length-1] (D) 是推荐的跨浏览器最快解决方案
  • 可变解决方案 arr.pop() (A) 和不可变方案 _.last(arr) (L) 速度较快
  • 对于长字符串,解决方案I、J较慢
  • 解决方案H、K(jQuery)在所有浏览器上最慢

enter image description here

细节

我对以下两种情况进行了解决方案测试:

  • 可变:ABC

  • 不可变:DEFGHI、J(我的方案),

  • 来自外部库的不可变方案:KLM

对于两种情况:

  • 短字符串 - 10个字符 - 您可以在 这里 运行测试
  • 长字符串 - 1百万个字符 - 您可以在 这里 运行测试

function A(arr) {
  return arr.pop();
}

function B(arr) {  
  return arr.splice(-1,1);
}

function C(arr) {  
  return arr.reverse()[0]
}

function D(arr) {
  return arr[arr.length - 1];
}

function E(arr) {
  return arr.slice(-1)[0] ;
}

function F(arr) {
  let [last] = arr.slice(-1);
  return last;
}

function G(arr) {
  return arr.slice(-1).pop();
}

function H(arr) {
  return [...arr].pop();
}

function I(arr) {  
  return arr.reduceRight(a => a);
}

function J(arr) {  
  return arr.find((e,i,a)=> a.length==i+1);
}

function K(arr) {  
  return $(arr).get(-1);
}

function L(arr) {  
  return _.last(arr);
}

function M(arr) {  
  return _.nth(arr, -1);
}






// ----------
// TEST
// ----------

let loc_array=["domain","a","b","c","d","e","f","g","h","file"];

log = (f)=> console.log(`${f.name}: ${f([...loc_array])}`);

[A,B,C,D,E,F,G,H,I,J,K,L,M].forEach(f=> log(f));
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js" integrity="sha256-VeNaFBVDhoX3H+gJ37DpT/nTuZTdjYro9yBruHjVmoQ=" crossorigin="anonymous"></script>

Chrome短字符串的示例结果

输入图像描述


这些数字是什么意思?越高越好吗? - Greggory Wiley
1
我甚至可以在你运行它们之前猜出结果,哈哈。但我认为在这种情况下性能并不重要。 - Ilya Gazman
这不是对问题的回答,问题本身也没有讨论性能。选择特定解决方案时,除了性能之外还有许多其他考虑因素。 - mikemaccana

95
通过使用length属性,可以获取数组中的最后一个元素。由于数组的计数从0开始,因此可以通过引用array.length - 1来选择最后一个元素。

const arr = [1,2,3,4];
const last = arr[arr.length - 1];
console.log(last); // 4

另一个选择是使用新的Array.prototype.at()方法,该方法接受一个整数值并返回该索引处的项。负整数从数组的最后一项开始计数,因此如果我们想要最后一项,只需传入-1

const arr = [1,2,3,4];
const last = arr.at(-1);
console.log(last); // 4

另一个选择是使用新的findLast方法。你可以在这里看到提案here(目前处于第4阶段)。

const arr = [1,2,3,4];
const last = arr.findLast(x => true);
console.log(last); // 4

另一个选项是使用Array.prototype.slice()方法,该方法将数组的一部分浅拷贝到一个新的数组对象中。

const arr = [1,2,3,4];
const last = arr.slice(-1)[0];
console.log(last); // 4


6
这篇文章为什么会有-1的评分? - Hicka
我认为应该是 arr.findLast(() => true);,因为你的版本无法“查找”假值,例如 0"",... - Thomas
我更新了我的回答@Thomas,感谢您的精彩评论。 - Ran Turner

83
这里是如何在不影响原始数组的情况下获取它。
a = [1,2,5,6,1,874,98,"abc"];
a.length; //returns 8 elements

如果您使用pop(),它将会修改您的数组。
a.pop();  // will return "abc" AND REMOVES IT from the array 
a.length; // returns 7

但是你可以使用这个方法,这样就不会对原始数组产生影响

a.slice(-1).pop(); // will return "abc" won't do modify the array 
                   // because slice creates a new array object 
a.length;          // returns 8; no modification and you've got you last element 

7
你应该使用 slice(-1).pop(),否则你会复制整个数组(实际上你只需要复制最后一个元素)。 - kritzikratzi
不需要使用 pop():只需执行 arr.slice(-1)[0] - Christophe Marois

60

“最清晰”的 ES6 方式(依我之见)是:

const foo = [1,2,3,4];
const bar = [...foo].pop();

如果我们没有使用展开运算符,.pop() 会修改 foo,但是使用展开运算符可以避免这种情况。
话虽如此,我也喜欢使用 foo.slice(-1)[0] 这种方法。


2
你也可以使用数组解构来使它更加符合ES6 ;) https://dev59.com/2nA75IYBdhLWcg3wlqET#46485581 - alex
60
请注意,该解决方案会复制整个数组。 - Brendan Annable
10
.slice(-1)[0]一样难读,但速度更慢。最好使用.slice - fregante
26
仅为了“简洁”的语法而复制整个数组,在我看来似乎有些愚蠢。甚至看起来也不那么美观。 - Jemar Jones

57

const [lastItem] = array.slice(-1);

Array.prototype.slice 和 -1 可以用来创建一个新的 Array,只包含原始 Array 的最后一项,然后你可以使用 Destructuring Assignment 来创建一个变量,使用那个新 Array 的第一项。

const lotteryNumbers = [12, 16, 4, 33, 41, 22];
const [lastNumber] = lotteryNumbers.slice(-1);

console.log(lotteryNumbers.slice(-1));
// => [22]
console.log(lastNumber);
// => 22


“.slice(-1)”的答案已经在多个场合中给出,最早可以追溯到2012年(https://dev59.com/2nA75IYBdhLWcg3wlqET#12099341),并且它的影响已经被详细讨论过了(不像这里)。请不要为了获得一些赞而重复回答。 - Dan Dascalescu
2
我认为这个答案是最好的。其他使用.slice(-1)的答案我见过都是使用[0]而不是解构。@diachedelic的评论建议使用这种解构方式,但在我看来,它应该成为一个答案而不是一个评论。还有很好的例子和链接。 - Marcus
是的,那些其他答案不同,丹,你错过了使用由slice(-1)产生的数组的解构赋值。 - Jamie Mason
1
这也允许您以简洁的语法选择例如最后两个项目:const [secondLast, last] = lotteryNumbers.slice(-2) - Nicolai Lissau

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