【问题标题】:Why can't I do array[-1] in JavaScript?为什么我不能在 JavaScript 中做 array[-1]?
【发布时间】:2019-06-01 15:18:59
【问题描述】:

在 Python 中,您可以这样做:

arr = [1,2,3]
arr[-1] // evaluates to 3

但是在 JS 中,你不能:

let arr = [1,2,3];
arr[-1]; // evaluates to undefined

问题是:为什么?

我知道绕过它的技巧(arr[arr.length-1]、修改数组原型等),但这不是重点。

我试图理解为什么在 EcmaScript 标准中仍然没有将负数组索引解释为从末尾开始的索引,尽管实现一个理解这一点的 JS 引擎似乎很容易(而且,整个Python 社区对这种表示法很感兴趣)。

我错过了什么?

【问题讨论】:

  • 向后兼容性很重要。
  • 因为他们没有选择让 JavaScript 那样工作?
  • @Herohtar 这正是我的问题——他们为什么这样做
  • 不这样做更有意义。 Python 规定负整数键与其他正整数索引相关。我认为这种抽象提供清晰的假设是幼稚的。
  • 我更新了my answer。使用新的 javascript .at() 方法,现在有一个官方直接的解决方案来解决这个问题。请参阅my answer。也许您想接受它作为最佳答案。

标签: javascript python arrays indexing


【解决方案1】:

你没有抓住重点,数组是对象(exotic object),-1 是一个有效的键。

var array = [1, 2, 3];

array[-1] = 42;

console.log(array);
console.log(array[-1]);

【讨论】:

  • 这就解释了。但是在数组中使用负索引是一种好的编程模式吗?我看不到任何不是 hack 的用途
  • @NinoFiliu Javascript 并不是因为它是一种有很多防护栏的语言,而是因为它的简单、尽管灵活且富有表现力的语义。它最初是一种脚本语言,让人们可以直接在标记中为他们的网站制作动画,当时每个人都认为 Web 应用程序将被编写为 Java 小程序。
  • @NinoFiliu 如果您正在使用数组,则使用负索引没有意义,您不应该这样做。例如,negative indices don't count toward the array length
【解决方案2】:

可以使用arr[-1] - 它会尝试访问arr 对象上的-1 属性,当奇怪的代码分配给负索引时,这是可能的。例如:

const arr = [1,2,3]
arr[-1] = 'foo';
console.log(arr[-1]);

Javascript 属性访问一直以这种方式工作 - 因此,更改内容以使 [-1] 引用 数组中的最后一项 将是一个重大更改,标准极力避免这种情况。 (请记住他们是如何退出 Array.prototype.flatten 名称的,因为它与仅在少数站点上仍然存在的极其陈旧和过时的 MooTools 版本不兼容 - 这会更糟)

【讨论】:

    【解决方案3】:

    正如其他人所说,在 Javascript 中,array[-1] 只是对array 的属性的引用(如length),通常为undefined(因为它没有被评估为任何值)。

    但有解决办法:

    更新:

    .at() 方法现在可在各种环境中使用:

    • Chrome / Edge / Chrome Android / WebView Android:v92+
    • Firefox / Firefox for Android:v90+
    • Opera:v78+
    • 节点:v16.6.0 (V8 9.2)+
    • Deno:v1.12+
    • More info ...

    at() 方法接受一个整数值并返回该索引处的项目,允许正整数和 整数。 负整数从数组的最后一项开始倒数。

    https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at

    检查您的浏览器是否支持:

    const array = [1, 2, 3]
    
    try {
        console.log(array.at(-1))  // 3
        console.log(array.at(-2))  // 2
        console.log(array.at(-3))  // 1
        console.log(array.at(-4))  // undefined
    } catch (e) {
        console.error("Sorry! Your browser doesn't support this feature yet!\nSee:\nhttps://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/at#browser_compatibility")
    }

    Compatibility


    使用.slice(-N)[0]:

    const array = [1, 2, 3]
    
    console.log(array.slice(-1)[0])  // 3
    console.log(array.slice(-2)[0])  // 2
    console.log(array.slice(-3)[0])  // 1

    Strings 中,您有另一个选择(而不是[0])。

    const string = 'ABC'
    
    console.log(string.slice(-1))      // 'C'
    console.log(string.slice(-2, -1))  // 'B'
    console.log(string.slice(-3, -2))  // 'A'

    或者使用.substr(-N, 1):

    const string = 'ABC'
    
    console.log(string.substr(-1))     // 'C'
    console.log(string.substr(-2, 1))  // 'B'
    console.log(string.substr(-3, 1))  // 'A'

    【讨论】:

    • 在内存方面的效率值得怀疑。array.slice 创建了一个新数组,因此您可能会增加一倍的内存消耗(最坏的情况)..
    • 请注意,Array.at 在桌面或移动版 Safari 上仍不受支持。
    【解决方案4】:

    因为大多数语言都像indexOf 函数返回-1 而不是不必要的异常。如果-1 是一个有效的索引,那么下面的代码将导致3 而不是undefined

    var arr = [1,2,3]
    console.log(arr[arr.indexOf(4)])

    恕我直言,Python 使负索引有效是一个错误,因为它会导致许多不直接直观的奇怪后果。

    【讨论】:

    • 这不是原因。数组索引启发式不是为了方便使用特定函数而设计的。如果有的话,反之亦然——首先定义低级行为(如数组索引),然后在该规则集中编写函数。参考:"indexOf() was added to the ECMA-262 standard in [ES5]"
    猜你喜欢
    • 2013-07-03
    • 1970-01-01
    • 2011-08-15
    • 2014-09-22
    • 2018-10-24
    • 2020-08-05
    • 2011-10-21
    相关资源
    最近更新 更多