89

在javascript中我定义了一个这样的数组

var arr = [1,2,3];

我也可以

arr[-1] = 4;

现在如果我这样做

arr = undefined;

我也失去了对arr[-1]值的引用。

所以对我来说,逻辑上似乎 arr[-1] 也是arr的一部分。

但是当我执行以下操作时(没有将 arr 设置为未定义)

arr.length;

它返回3而不是4

所以我的观点是,如果数组可以与负索引一起使用,这些负索引也应该是它们长度的一部分**。我不知道可能是我错了,或者我可能遗漏了一些关于数组的概念。

4

8 回答 8

119

所以对我来说,逻辑上似乎 arr[-1] 也是 arr 的一部分。

是的,但不是你想象的那样。

您可以将任意属性分配给数组(就像 JavaScript 中的任何其他对象一样),这就是您在“索引”数组-1并分配值时所做的事情。由于这不是数组的成员,只是一个任意属性,因此您不应期望length考虑该属性。

换句话说,下面的代码做同样的事情:

​var arr = [1, 2, 3];

​arr.cookies = 4;

alert(arr.length) // 3;
于 2012-11-29T04:01:29.973 回答
26

length属性将返回比分配的最高“索引”高一的数字,其中数组“索引”是大于或等于零的整数。请注意,JS 允许“稀疏”数组:

var someArray = [];
someArray[10] = "whatever";
console.log(someArray.length); // "11"

当然,如果没有元素,那么length就是0。另请注意,如果您用于删除最高元素,length则不会更新。delete

但是数组是对象,因此您可以为属性分配其他任意属性名称,包括负数或分数:

someArray[-1] = "A property";
someArray[3.1415] = "Vaguely Pi";
someArray["test"] = "Whatever";

请注意,即使您提供像-1. (就此而言,正整数索引也变为字符串。)

数组方法,如.pop(),.slice()等,仅适用于零或更高的整数“索引”,而不适用于其他属性,因此length在这一点上是一致的。

于 2012-11-29T04:09:05.153 回答
8

请注意,当您使用位置(或 0)索引时,值将放置在数组中:

var array = [];

array[0] = "Foo";
array[1] = "Bar";

// Result: ["Foo", "Bar"]
// Length: 2

当您添加非索引值(不是 0-9+)时,情况并非如此:

var array = [];

array[0]  = "Foo";
array[1]  = "Bar";
array[-1] = "Fizzbuzz"; // Not a proper array index - kill it

// Result: ["Foo", "Bar"]
// Length: 2

仅当您按照规则进行操作时,才会将值放置在数组中。如果你不这样做,他们就不会被接受。然而,它们在 Array 对象本身上被接受,这在 JavaScript 中几乎任何东西都是如此。即使["Foo", "Bar"]是我们数组中唯一的值,我们仍然可以访问"Fizzbuzz"

array[-1]; // "Fizzbuzz"

但请再次注意,这不是数组值的一部分,因为它的“索引”无效。相反,它只是作为另一个成员添加到数组中。我们可以以相同的方式访问其他数组成员:

array["pop"]; // function pop() { [native code] }

请注意,我们正在访问pop数组上的方法,这告诉我们这包含本机代码。我们不是使用“pop”键访问任何数组值,而是数组对象本身的成员。我们可以通过循环访问对象的公共成员来进一步确认这一点:

for (var prop in array) 
    console.log(prop, array[prop]);

吐出以下内容:

 0 Foo
 1 Bar
-1 Fizzbuzz

再说一遍,它object上,但不在array中。

真棒问题!导致我肯定做了双重考虑。

于 2012-11-29T04:16:42.930 回答
5

如果您确实希望将负索引和其他索引包含在长度中,请自己创建功能:

function getExtendedArray() {
    var a = [];

    Object.defineProperty(a, 'totalLength', { 
        get : function() { return Object.keys(a).length; }
    });

    return a;
}

然后例如:

var myArray = getExtendedArray();
console.log(myArray.totalLength); // 0
myArray.push("asdf");
myArray[-2] = "some string";
myArray[1.7777] = "other string";
console.log(myArray.totalLength); // 3
于 2013-07-18T16:22:27.390 回答
4

JavaScript 中的数组实际上是对象。它们只是从 Array 构造函数中创建的原型。

数组索引实际上是哈希图中的键,所有键都转换为字符串。您可以创建任何键(即“-1”),但 Array 上的方法被定制为像数组一样工作。所以length不是对象的大小,而是只保证大于最大的整数索引。同样,打印arr只会列出整数键 >= 0 的值。

更多信息在这里。

于 2012-11-29T04:05:42.737 回答
4

数组只是 JS 中一种特殊的Object。有一种特殊的语法,很好,因为它允许我们有效地使用它们。想象一下以这种方式编写数组字面量是多么乏味:

const array = {0: 'foo', 1: 'bar', 2: 'baz'} //etc...

它们仍然是对象。所以如果你这样做:

const myArray = [42, 'foo', 'bar', 'baz'];

myArray[-1] = 'I am not here';
myArray['whatever'] = 'Hello World';

这些非整数属性将附加到一个对象(数组是),但某些本机方法(如Array.length.

您可以假设本机 'length' 方法是一个 getter,它计算所有属性(索引属性,而值是实际)可转换为正整数或零。像这样的伪实现:

由于规范,本机length方法 - 作为getter ( exampleArray.length) - 将检查所有“小于 2 32的非负整数”键,获取最大的键并返回其数值 + 1。

作为setter ( exampleArray.length = 42),如果给定长度大于非负整数键的实际数量,它将为“缺失”索引创建一些空槽,或者删除所有不大于给定长度。

伪实现:

const myArray = {
  '-1': 'I am not here', // I have to use apostrophes to avoid syntax error
  0: 42,
  1: 'foo',
  2: 'bar',
  3: 'baz',
  whatever: 'Hello World',

  get myLength() {
    let highestIndex = -1;
    for (let key in this) {
      let toInt = parseInt(key, 10);
      if (!Number.isNaN(toInt) && toInt > -1) {
        // If you're not an integer, that's not your business! Back off!
        if (toInt > highestIndex) highestIndex = toInt;
      }
    }
    return highestIndex + 1;
  },
  set myLength(newLength) {
    /* This setter would either:
      1) create some empty slots for 'missing' indices if the given length is greater than the actual number of non-negative-integer keys
      2) delete all non-negative-integer keys (and their values) which are not greater then the given length.
    */
  }
}

console.log(myArray.myLength); // 4

myArray[9] = 'foobar';

console.log(myArray.myLength); // 10

于 2018-11-05T11:36:15.990 回答
1

根据 MDN:

length 属性的值是一个带正号且值小于 2 的 32 次方 (232) 的整数

在 Javascript 中,您可以在您创建的任何对象上设置属性。

var array = new Array();
array = [1,2,3];
array["boom"] = "pow";

同样,当您设置负索引时,它会将其作为属性存储在数组中,而不是索引的一部分。

array[-1] = "property does not add to array length";

这就是为什么长度没有反映它,而是一个 for..in 循环显示它的原因。

于 2012-11-29T04:25:42.400 回答
-1

当您使用非正数或非数字索引时,数组表现为具有键值对的关联数组。

要遍历数组,您可以使用

for(var index in myArray) {
  document.write( index + " : " + myArray[index] + "<br />");
}
于 2012-11-29T04:06:37.333 回答