为什么我可以将命名属性添加到数组中,就像它是一个对象一样?

IT技术 javascript arrays object javascript-objects
2021-01-27 22:03:53

以下两个不同的代码片段对我来说似乎是等价的:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

var myObject = {'A': 'Athens', 'B':'Berlin'};

因为它们的行为相同,而且typeof(myArray) == typeof(myObjects)(都产生“对象”)。

这些变体之间有什么区别吗?

6个回答

实际上,javascript 中的所有内容都是一个对象,因此您可以通过在其上设置任意属性来“滥用”一个Array对象。但这应该被认为是有害的数组用于数字索引数据 - 对于非数字键,使用对象。

这是一个更具体的例子,为什么非数字键不“适合”数组:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";

alert(myArray.length);

这不会显示“2”,而是“0”——实际上,没有向数组添加任何元素,只是向数组对象添加了一些新属性。

myArray.length 返回数组中最后一个元素的数字索引/键,但不是元素的实际数量。Array 对象的属性是否与数组值不同?
2021-03-25 22:03:53
@Olivier,你所说的“错误”也可以是一个很棒的“功能”。您可以向数组添加标题和描述,而不会影响其内容或长度,也无需将它们包装在具有title,descriptionitems属性的对象中这完全取决于您对语言的了解程度以及使用方式。
2021-04-01 22:03:53
下次有人说 JavaScript 是一种很好的开发语言时,我会向他展示这个示例。谢谢你。
2021-04-05 22:03:53
在数组上使用自定义属性本质上并不是错误的。一旦你这样做,就期望它们充当数组成员,这是错误的。它们是数组属性,而不是成员,因此不受数组方法的影响。这实际上是上述链接文章的作者在评论中所说的。现在,平心而论,我建议不要将其作为一种实践,因为它可能会使使用您的代码的人感到困惑。或者,如果他们刚刚开始,就会以榜样的力量将他们置于危险的道路上。但我不会说 JavaScript 不好,因为它允许大多数人不希望被允许的东西。
2021-04-06 22:03:53
我只是想说明如果你只是把它当作一个普通对象来对待,那么 Array 对象的预期语义就会被滥用。不过,链接的文章做得更好:)
2021-04-07 22:03:53

在 JS 中数组是对象,只是稍作修改(还有一些功能)。

功能如:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
虽然我不认为列出的所有函数都是内置于每个 JS 实现中的,但您明白这一点。另一个区别是不同的原型(这些额外的功能暗示了这一点)。
2021-03-10 22:03:53

我认为,我对以前的回答过于隐喻和神秘。澄清如下。

Array、Boolean、Date、Function、Number、RegExp、String 的实例是一个对象,但增强了特定于每种类型的方法和属性。例如,数组具有预定义的length属性,而通用对象则没有。

javascript:alert([].length+'\n'+{}.length)

显示

0
不明确的

从本质上讲,FF Gecko 解释器还通过评估语言构造的明显差异来区分数组和通用对象。

javascript:
  ra=[  "one",   "two",   "three"]; ra.a=4;
  ob={0:"one", 1:"two", 2:"three"}; ob.a=4;
  alert(
    ra            +"\n\n"+
    ob            +"\n\n"+
    ra.toSource() +"\n\n"+
    ra.a          +"\t .toSource() forgot me! \n\n"+
    ra.length     +"\t and my length! \n\n"+
    ob.toSource());
  ps=""; for(i in ra)ps+=i+" "; alert(ps);  /* NB .length is missing! */
  ps=""; for(i in ob)ps+=i+" "; alert(ps);

显示

一二三

[对象对象]

[“一二三”]

4 .toSource() 忘了我! 

3和我的长度! 

({0:"一", 1:"二", 2:"三", a:4})

0 1 2 a0 1 2 a

关于所有对象都是函数的说法:

将任意对象实例用作函数,例如123()or"abc"()[]()or{}()obj()whereobj是除 之外的任何类型Function语法和语义上都不正确,因此任意对象 INSTANCE 不是 a Function但是,给定一个对象obj并且它的类型为 as Array, Boolean, Date, ...,如何obj变成 as Array, Boolean, Date, ...什么是Array, Boolean, Date, ...

javascript:
    alert([Array, Boolean, Date, Function, 
              Number, Object, RegExp, String] . join('\n\n') );

显示

function Array() {
    [native code]
}

function Boolean() {
    [native code]
}

function Date() {
    [native code]
}

function Function() {
    [native code]
}

function Number() {
    [native code]
}

function Object() {
    [native code]
}

function RegExp() {
    [native code]
}

function String() {
    [native code]
}

在任何情况下,毫无疑问,对象类型都表现为function定义,因此声明所有对象都是函数!(诙谐的是我故意模糊和模糊了对象实例与其类型的区别!不过,这表明“你不能没有另一个”,对象和功能!大写强调类型为反对实例。)

函数范式和对象范式似乎都是 JS 解释器低级内置原语(例如MathandJSON和 )的编程和实现的基础true

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));

显示

[object Math]

[object JSON]

(new Boolean(true))

在开发 Javascript 的时候,以对象为中心的编程风格(OOP's - 面向对象的编程风格 - “'s”是我自己的双关语!)正在流行,解释器同样被命名为 Java 以赋予它更大的可信度. 函数式编程技术被归为更抽象和深奥的考试,研究自动机、递归函数、形式语言等的理论,因此不那么令人愉快。然而,这些形式考虑的优势在 Javascript 中很明显,特别是在 FF 的 Gecko 引擎(即.toSource())中实现的。


Function 的 Object 定义特别令人满意,因为它被定义为递推关系!使用它自己的定义来定义!

function Function() { [native code] }
并且由于一个函数是一个对象,所以同样的情绪也适用于
function Object() { [native code] }

大多数其他定义都停止为静态终端值。然而,eval()是一个特别强大的原语,因此字符串也可以嵌入任意功能。

再次注意,上面使用的白话掩盖了对象类型和实例的区别。

JavaScript 中的所有内容都是除基本类型之外的对象。

代码

var myArray = Array();

创建 Array 对象的实例,而

var myObject = {'A': 'Athens', 'B':'Berlin'};

创建一个 Object 对象的实例。

试试下面的代码

alert(myArray.constructor)
alert(myObject.constructor)

所以你会看到不同之处在于对象构造函数的类型。

Array 对象的实例将包含 Array 原型的所有属性和方法。

您可以将命名属性添加到 JavaScript 中的几乎所有内容,但这并不意味着您应该这样做。 Array在 javascript 中应该用作列表,如果你想要一个关联数组,请使用Object

请注意,如果您真的想使用Array具有命名属性的属性而不是Object那些属性,则这些属性将无法在for...of循环中访问,并且当 JSON 编码它以传递它时,您也可能会得到意想不到的结果。请参阅下面的示例,其中所有非数字索引都被忽略:

let arr = [];
let obj = {};

arr['name'] = 'John';
obj['name'] = 'John';

console.log(arr);    // will output [name: "John"]
console.log(obj);    // will output {name: "John"}

JSON.stringify(arr); // will return [] <- not what you expected
JSON.stringify(obj); // will return {"name":"John"}