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

pri*_*bel 103 javascript arrays object javascript-objects

以下两个不同的代码片段似乎与我相同:

var myArray = Array();
myArray['A'] = "Athens";
myArray['B'] = "Berlin";
Run Code Online (Sandbox Code Playgroud)

var myObject = {'A': 'Athens', 'B':'Berlin'};
Run Code Online (Sandbox Code Playgroud)

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

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

Pau*_*xon 130

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

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

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

alert(myArray.length);
Run Code Online (Sandbox Code Playgroud)

这不会显示'2',而是'0' - 实际上,没有元素添加到数组中,只是添加了一些新属性到数组对象.

  • 下次有人说JavaScript是一种很好的语言,我会向他展示这个样本.谢谢. (10认同)
  • myArray.length返回数组中最后一个元素的数字索引/键,但不返回实际的元素数.Array对象的属性是否与数组值不同? (3认同)
  • 在数组上使用自定义属性本质上并不是错误的。错误的是一旦你这样做了,期望它们充当数组成员。它们是数组属性,而不是成员,因此不受数组方法的影响。这实际上是上述链接文章的作者在评论中所说的。现在,平心而论,我建议不要将其作为一种做法,因为它可能会让使用您的代码的人感到困惑。或者,如果他们才刚刚开始,这将使他们走上危险的道路,以身作则。但我不会说 JavaScript 不好,因为它允许做大多数人不希望允许的事情。 (3认同)
  • +1 tao:如果“它可能会让使用你的代码的人感到困惑”,那么这本质上是一种容易出现更多问题的语言 (2认同)

Cas*_*sey 14

在JS数组中是对象,只是略微修改(带有更多函数).

功能如下:

concat
every   
filer
forEach
join
indexOf
lastIndexOf
map
pop
push
reverse
shift
slice
some
sort
splice
toSource
toString
unshift
valueOf 
Run Code Online (Sandbox Code Playgroud)


Eki*_*kim 6

我认为,我以前的回答太隐喻和含糊不清.澄清如下.

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

javascript:alert([].length+'\n'+{}.length)
Run Code Online (Sandbox Code Playgroud)

显示器

0
undefined

从本质上讲,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);
Run Code Online (Sandbox Code Playgroud)

显示

one,two,three

[object Object]

["one", "two", "three"]

4    .toSource() forgot me! 

3    and my length! 

({0:"one", 1:"two", 2:"three", a:4})

0 1 2 a0 1 2 a.

关于所有对象都是函数的声明:

它既不语法也不语义正确使用任意对象实例为像一个函数123()"abc"()[](){}()obj()其中,obj比其它任何类型的Function,所以一个任意对象实例不是Function.但是,给定一个对象obj和它的类型Array, Boolean, Date, ...,怎么obj会成为一个Array, Boolean, Date, ...?什么是Array, Boolean, Date, ...

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

显示器

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]
}
Run Code Online (Sandbox Code Playgroud)

在每种情况下,没有模棱两可,对象类型表现为一个function定义,因此声明所有对象都是函数!(诙谐的是我故意模糊和模糊了对象实例与它的类型的区别!尽管如此,这表明"你不能拥有一个没有另一个",对象和函数!大写强调类型为与实例相反.)

两者的功能和对象的范式似乎是编程和执行JS解释的低水平内置原语,比如基本的MathJSONtrue.

 javascript:alert([Math, JSON, true.toSource()].join("\n\n"));
Run Code Online (Sandbox Code Playgroud)

显示器

[object Math]

[object JSON]

(new Boolean(true))
Run Code Online (Sandbox Code Playgroud)

在Javascript开发的时候,以对象为中心的编程风格(OOP的 - 面向对象的编程风格 - "我的自己的双关语!")很流行,并且解释器同样用Java命名,以使其具有更高的可信度.功能编程技术被降级为更抽象和深奥的考试,研究自动机,递归函数,形式语言等的理论,因此不适合.然而,这些正式考虑的优势在Javascript中明显体现出来,特别是在FF的Gecko引擎中实现(即.toSource()).


函数的Object定义特别令人满意,因为它定义为递归关系!使用它自己的定义定义!

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

大多数其他定义停顿在静态终端值上.但是,它eval()是一个特别强大的原语,因此String也可以嵌入任意功能.

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


Das*_*alo 5

JavaScript中的所有内容都是除了原始类型之外的对象.

代码

var myArray = Array();
Run Code Online (Sandbox Code Playgroud)

创建Array对象的实例

var myObject = {'A': 'Athens', 'B':'Berlin'};
Run Code Online (Sandbox Code Playgroud)

创建Object对象的实例.

请尝试以下代码

alert(myArray.constructor)
alert(myObject.constructor)
Run Code Online (Sandbox Code Playgroud)

所以你会看到区别在于对象构造函数的类型.

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


use*_*314 5

您可以将命名属性添加到 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"}
Run Code Online (Sandbox Code Playgroud)