在JavaScript数组中添加一个属性

66

数组默认具有“length”属性。

我能够添加自定义属性吗?

而不必将它们转换为对象。


6
“add custom properties without having to make them objects?”的意思是如何在不将它们作为对象创建的情况下添加自定义属性?数组本身就是对象,几乎所有JS中的元素都是对象。那么这些属性是什么呢?能否进一步解释一下? - Joseph
它们是对象。只是一种特殊类型的对象。例如,函数也是一种特殊类型的对象。 - ThiefMaster
1
请参考这个相关问题,了解为什么不应该这样做。 - Ja͢ck
5个回答

76
var arr = [1,2,3,4,5];
arr.prop = 'value';

在JavaScript中,数组已经是对象——它们只是具有一些额外功能和特殊字面量语法。


我的属性会随着其他元素一起迭代吗?因为在console.log中,我没有看到它与"length"等不透明文本一起。 - ellabeauty
11
当您使用for(var key in arr)时,数组中的属性会被迭代。但是,这不应该在数组上使用,所以对您来说这不应该是一个问题。使用for(var i = 0; i < arr.length; i++)进行迭代将不包括这些属性(它们甚至不会添加到数组的长度中)。 - ThiefMaster
2
如果使用 for in 循环,该属性将被迭代。在普通的 for 循环中,它不会被迭代,因为您只能通过其数组索引访问每个成员。它也不会被本机数组 ES5 方法(例如 forEach)迭代。 - Kevin Ennis
3
以上全部属实。例如,stringName.match(/regex/) 返回一个数组,但是该数组也有两个额外的属性供您参考——“返回的数组有一个额外的input属性,其中包含解析过的原始字符串。此外,它还有一个index属性,表示匹配在字符串中以零为基础的索引。“但是,当您遍历返回值或使用console.log输出结果时,结果集不包含额外的属性,只包含数组本身的元素。 - CtheGood
2
console.log将显示属性,如果您只想访问属性,则可以执行keys = Object.keys(arr).slice(arr.length);。然后,您可以使用for in迭代仅限于键。注意但是,当您将属性分配给数组时,应避免仅使用数字,因为它们将被解释为数组索引。例如(arr['7']将与arr[7]混淆,如果您的对象继承自Array)。 - Leathan

47

正如其他答案所述,这是完全可能的,因为JavaScript中的数组只是对象。然而,问题仍然存在,即它是否是一个好主意。

那是一个“编码风格”问题,所以很难客观地说,但Douglas Crockford并不反对它(至少在某些情况下)。在JavaScript:The Good Parts中,他实际上使用了将“total”方法添加到数组的示例。

Because an array is really an object, we can add methods directly to an individual array:

// Give the data array a total function

data.total = function () {
    return this.reduce(add, 0);
};

total = data.total();    // total is 108

Since the string 'total' is not an integer, adding a total property to an array does not change its length.

(第62页,Crockford的《JavaScript精粹》,可在谷歌图书上找到)

然而,值得一提的是这些额外属性不包括在JSON序列化中,如果你执行类似于arr = arr.slice(1);的操作,它们会被丢弃。


感谢您包含参考资料。 - Tyler Collier
2
此外,如果数组经过其原型方法(map、filter等)之一,该属性将不会传递到新数组中,因为该方法被放置在Array的实例上。这可能是预期的,但在这种情况下可能并不理想? - Daniel Lizik
内置的 RegExp.prototype.exec() 返回以下类似的数组。尝试 <someRegExp>.exec(<someString>),您将获得一个数组,例如 [<fullResult>, <subStrResults>, ..., index: <Number>, input: <origStr>]。请参见 MDN - tjfwalker

9
如果您想将其隐藏在数组中等(至少这是我要找的):
Object.defineProperty( targ, "myVal", { enumerable: false, writable: true } );

那么数组不会将其添加到长度中,所以我想你可以说它是一个属性而不是一个值。

如果你想查看对象中的键,例如Object.keys无法查看它,但Reflect.ownKeys()可以。

defineProperty的Reflect版本将返回成功或失败,而Object的版本则返回传递的对象。

请记住,Reflect.preventExtensions()将(如其名称所示)阻止您或他人扩展它们。


4

数组是对象,因此您可以向其添加自己的属性:

var arr = [1, 2, 3];
arr.foo = 'bar';

扩展其他答案,以下是迭代数组(不包括自定义属性)的几种方法。

  1. Using a standard for loop

    for (let i = 0; i < arr_length; i++)
        console.log(arr[i]);
    

    or if not using ES6:

    for (var i = 0; i < arr.length; i++)
        console.log(arr[i]);
    
  2. Using the for ... of loop (ES6+)

    for (let el of arr)
        console.log(el)
    
  3. Using Array.prototype.forEach (ES6+)

    arr.forEach(el => console.log(el));
    

    or

    arr.forEach(function(el) {
        console.log(el);
    });
    

遍历数组,包括所有属性(例如自定义属性、length):

for (let prop in arr)
    console.log(prop);

如果不使用ES6:

for (var prop in arr)
    console.log(prop);

2

是的,您可以通过声明它们并使用Array.prototype扩展数组来将它们添加到对象中。

var j = new Array();
j.yourprop = "foo";

14
我更喜欢使用 var j = (function(array){return new array();}(window.Array))。这段代码的意思是创建一个新的数组对象,将其分配给变量j。 - Kevin Ennis
1
我更喜欢使用 var j = function(array){return new array();}(window.Array),这样可以延长我的 () 按键寿命。 - Déjà vu

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