从索引不以0开始的数组中获取第一个元素

6

我正在使用一个JavaScript库,它返回不以零开始的数组,比如从26或1500开始。我想做的是编写一个方法,无论索引号是否以0或其他任何数字开头,都可以获取该数组中的第一个元素。

在JavaScript中是否有这样的方法?


1
那是什么 javascript 库?你到目前为止尝试了什么?请提供你的代码示例。 - Andrei Zhytkevich
6个回答

6

我建议使用Array#some。它可以获取数组中第一个非稀疏元素和它的索引。如果在回调函数中返回true,则迭代会立即停止:

var a = [, , 22, 33],
    value,
    index;

a.some(function (v, i) {
    value = v;
    index = i;
    return true;
});

console.log(index, value);


@T.J.Crowder,它可以工作,顺便提一下,即使是undefined值也可以。 - Nina Scholz

2
下面的信息通常是有用的,但对于OP列出的问题,Nina的答案是远远更好的解决方案。
那些被称为“稀疏”数组,是你可能想在数组上使用for-in的少数情况之一。
请记住,在JavaScript中,数组是对象,而数组条目是由符合特定条件的名称(数组索引)键入的属性。因此,我们可以使用发现对象属性的功能来查找稀疏数组中的索引。
例如:for-in
for (var n in theArray) {
    if (theArray.hasOwnProperty(n) && isArrayIndex(n)) {
        // Use theArray[n]
    }
}

这篇回答展示了如何确定n是一个数组下标,而不是其他属性。一个非常技术化的定义会是:
function isArrayIndex(n) {
    return /^0$|^[1-9]\d*$/.test(n) &&
           n <= 4294967294;
}

"...但对于我们大多数人来说足够好的定义将是"
function isArrayIndex(n) {
    return !isNaN(parseInt(n, 10));
}

同样地,您可以使用Object.keys; 因为它只查看自己的可枚举属性,所以您不需要进行hasOwnProperty检查:
Object.keys(theArray).forEach(function(n) {
    if (isArrayIndex(n)) {
        // ...
    }
});

请注意,从官方上讲,这两个并没有特定的顺序,甚至在ES2015(“ES6”)中也是如此。因此,在理论上,您可能会看到数字顺序不正确的索引。在现实世界中,我从未见过任何一个稍微现代化的JavaScript引擎按顺序返回数组索引。它们不是必需的,但是我尝试过的每一个都是这样做的。
因此,从官方上讲,您需要获取完整的列表,然后找到其中的最小值:
var min = Object.keys(theArray).reduce(function(min, n) {
    var i = parseInt(n, 10);
    return isNaN(i) || (min !== undefined && min > i) ? min : i;
}, undefined);

这将会在数组为空时给你返回 `undefined`,否则返回最小的索引。但如果你想做出这样的假设,即你会按照数字顺序获取键:
// Makes an assumption that may not be true
var min = +Object.keys(theArray).filter(isArrayIndex)[0];

如果您使用的是完全更新的 JavaScript 引擎,则可以依赖 Object.getOwnPropertyNames 返回的顺序,该方法需要按顺序列出数组索引。
var min = +Object.getOwnPropertyNames(theArray).filter(isArrayIndex)[0];

@azelix:非常感谢,但是看一下Nina的回答——她有一个更好的方法来获取第一个索引。 - T.J. Crowder

1
我猜想 Array.prototype.some() 的另一种替代方法是 Array.prototype.findIndex() 方法。这些方法比仅使用过滤器的速度快得多,而且不会改变数组和索引。

var arr = new Array(1000),
     fi = -1;
arr[777] = 1453; // now we have a nice sparse array
fi = arr.findIndex(f => f !== void 0); // void 0 is the perfect undefined
console.log(fi);
console.log(arr[fi]);


1
这需要比Nina的Array#some更多的回调调用(因为findIndex访问稀疏元素),而且您的条件过滤掉了存在但值为undefined的条目,而不仅仅是缺少条目。 - T.J. Crowder
@T.J. Crowder:因为findIndex访问稀疏元素。实际上它并不会,如果真的这样做是非常没有意义的。请先阅读第一段 https://developer.mozilla.org/tr/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex#Description - Redu
你真的认为如果我不确定,我会说那个吗?如果我没有检查过?在评论之前,我已经检查了规范并进行了实验验证。https://jsfiddle.net/hwk7fuah/ 我很抱歉MDN误导了你,当这种事情发生时,我很讨厌,但你可能需要花点时间进行快速测试,而不是咄咄逼人。 :-) MDN大多数时候都非常好,但它是社区编辑的,有时像那样的错误也会出现。我已经修复了它。 - T.J. Crowder
@T.J. Crowder:根据“undefined”注释。出于某种原因,我正在使用void 0,并且它是void 0 ===“undefined”// false,因此如果OP在数组中有“undefined”作为第一个非稀疏元素,他仍将得到它。我怀疑OP不会对此感兴趣,因为他的问题表述使我们理解他对未定义的项目不感兴趣,而稍微有可能他对“undefined”项目感兴趣。这是我的理解。 - Redu
"并且世界和平将再次恢复" 冷静下来。 - Nina Scholz
显示剩余8条评论

1
使用过滤函数对数组进行操作,可以得到一个规范化的数组。
var fullArray = array.filter(function(n){
    return n != undefined;
});
fullArray[0]

这里的答案可能会帮助你决定如何在Javascript中删除数组中的空元素

1
如果这很重要,你会失去索引。 - Nina Scholz
实际上,这过滤了两件完全不同的事情:缺失条目(因为filter根本不访问它们),以及存在但值为undefined的条目。如果您只想过滤掉缺失条目,请使用var fullArray = array.filter(function() { return true; }); - T.J. Crowder

1
const arr = [0,1,2]

// 使用解构来获取第一个元素

let [first] = arr

// 加号:使用解构获取最后一个元素

let [first] = [...arr].reverse()

0

使用这段代码,您可以找到第一个已分配值的索引,然后从数组中获取该值:

var a = [, , 22, 33];
var value = a.find((v, i) => i in a);
console.log(value);
/* ---------------------------------------------- */
var i = 0
while (!(i in a) && i < a.length) i++; // If i === a.length then the array is emtpy
console.info(i, a[i]);

第一种实现使用Array.prototype.find,这样可以减少变量的使用,因此更加简洁,但是要找到索引,您应该在数组上调用indexOf

但是第二种方法有点老式,但可以轻松获得索引而不需要额外的努力。


顺便说一下,Nina's 似乎更好。 (可以缩短吗?)


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