【问题标题】:Are Javascript arrays primitives? Strings? Objects?Javascript 数组是原语吗?字符串?对象?
【发布时间】:2011-06-30 05:18:20
【问题描述】:

数组仅仅是伪装的对象吗?为什么/为什么不?它们以什么方式(这样/不是)?

我一直认为 JS 中的数组和对象本质上是相同的,主要是因为访问它们是相同的。

var obj = {'I': 'me'};
var arr = new Array();
arr['you'] = 'them';

console.log(obj.I);
console.log(arr.you);
console.log(obj['I']);
console.log(arr['you']);

我是否误导/误会/错误?关于 JS 字面量、原语和字符串/对象/数组/等等,我需要了解什么?

数组/对象仅仅是变相的字符串吗?为什么/为什么不?它们以什么方式(这样/不是)?

【问题讨论】:

  • var arr = ['you':'them']; 这不是有效的语法
  • @Robert Harvey - 我试图澄清我的理解。符号是否表示重要性? “数组”与 Javascript 中的对象、字符串等有根本不同吗?我认为这是一个公平的调查。
  • @Martti - 非常正确。那么,与关联数组(或对象)相比,Javascript 数组始终是索引数组,这就是原则上的区别吗?
  • Ecmascript 语言规范在这里:ecma-international.org/publications/standards/Ecma-262.htm。 Ecmascript 和 Javascript 本质上是同一种语言。我能找到的所有 EcmaScript 和 Javascript 语言规范都说数组是对象。
  • @Robert Harvey - 我很感激。我正在寻找指导,一个“这是最好的理解方式”意义上的答案。我不确定是否可以在标准中找到该答案,尽管它有助于理解。我还要注意,我认为这在 SO 中没有得到充分的回答。我希望有人能得到启发,并在回答中真正做到这一点。

标签: javascript arrays javascript-objects


【解决方案1】:

数组不是 Javascript 中的原语,它们是对象。关键区别在于,因此,当您将数组传递给函数时,它是通过引用而不是值传递的。

所以是的!数组是 javascript 中的对象,具有完整的 Array.prototype 和所有内容(尽管不要碰它......)

混淆来自于 javascripts 允许您以两种方式访问​​对象属性的事实:

myObj.attribute 要么 myObj["属性"]

真正使数组成为数组的原因与存储数据的方式无关——任何对象都可以使用用于存储数组的语法来存储值——使数组成为数组的原因在于数组方法(例如 shift() 和 sort())是为 Array.prototype 定义的。

【讨论】:

  • 这和 Javascript 中的对象有区别吗?
  • 更正:数组的引用是传值的。
  • @The Scrum Master 很确定这就是人们所说的通过引用传递的意思......对吗?
  • “真正使数组成为数组的原因与您存储数据的方式无关” - 我喜欢这个答案只是因为它回答了我关于为什么对象/数组在 JS 中令人困惑的想法。跨度>
【解决方案2】:

对象是从字符串键到值的无序映射,数组是值的有序列表(带有整数键)。这是主要的区别。它们都是非原始的,因为它们由多个值组成,这也意味着 JavaScript 中的引用传递。

不过,数组也是一种对象,因此您可以为它们附加额外的属性,访问它们的原型等等。

在您修改后的示例中,您只是利用了数组实际上是一个对象这一事实,即您可以在它们上设置任何属性。你不应该那样做。如果您不需要有序的值列表,请使用普通对象。

【讨论】:

  • 最后一个“如果您不需要有序的值列表,请使用普通对象。”很有趣,马蒂。为什么?
  • @Jared:因为如果您不打算使用它提供的功能,则无需创建数组。这只是令人困惑。
  • @Jared:当你说“数组”时,任何程序员都会认为你需要一个有序列表。如果你不需要一个,说“数组”只会让任何阅读你的代码的人感到困惑。从技术角度来看,它不应该有太大的区别,开销(如果有的话)应该是微不足道的。还有一件事:你经常使用 PHP 吗?
  • @Jared:对不起,我不明白你想让我帮你理解什么。
  • @Jared:不,我宁愿去睡觉。不过有一件事;您应该清楚地区分变量和值。它们是两种不同的东西。如果您想了解有关对象如何工作的所有细节,请阅读 ECMAScript 标准(我想我在上面的评论中看到了指向它的链接)
【解决方案3】:

尽量简述我认为最重要的一点:数组有许多对象没有的方法。其中:

  • 长度
  • 推
  • 流行音乐

声明为var x = {foo:bar} 的对象无法访问 .length() 方法。它们都是对象,但数组是一种具有上述方法的超集。

我觉得这在解释方面甚至不接近 Crockford 标准,但我尽量简洁。

如果您想快速获得一些结果,请打开 Firebug 或您的 javascript 控制台并尝试使用 Array.prototype 和 Object.prototype 来查看一些详细信息

更新:在您的示例中,您声明一个数组,然后执行:

foo['bar'] = 'unexpectedbehaviour';

会产生意想不到的结果,并且不会在简单的循环中可用,例如:

var foo=[0,1];
foo['bar'] = 2;

for(var i=0;i<foo.length;i++){
    console.log(foo[i]);
}

//outputs: 
//0
//1

数组可以像对象一样接受foo['bar']=x 或foo.bar=y,但不一定可以像上面突出显示的那样循环。

我并不是说您不能遍历对象的属性,只是在使用数组时,您正在使用该独特的功能并且应该记住不要混淆。

【讨论】:

  • @connrs 不正确。数组可以像任何其他对象一样具有属性:var arr = []; arr.foo = 'Totally fine!';
  • 小心connrs。数组具有这些方法,因为它们是对象,其原型已被赋予这些功能。
  • @Šime Vidas:确实,但是 var foo=[0,1]; foo.bar=2; for(var i=0;i&lt;foo.length;i++){console.log(foo[i]);} 不会像预期的那样对 JavaScript 新手开发者起作用
  • @slifty:确实。数组字面量是我上面提到的对象。数组继承自 Array 原型方法,例如长度 push 和 pop,纯 Object 字面量不存在
  • @connrs 在您的回答中您说这是无效的:foo['bar'] = 'totallyinvalid'; 但事实并非如此。这是有效的。这就是我的观点。
【解决方案4】:

字符串可以是原始的也可以是对象,这取决于它们的声明方式。

var str = 'yes';

给你一个原始的,而,

var str = new String('yes');

会给你一个字符串对象。


所有数组都是相同的(无论它们是用 [] 还是 new Array() 定义的),都是对象类型,并且继承自“Array”对象的原型。 Javascript 中没有真正的类,一切都是对象,并且有一个系统定义的对象,称为 Array。它有一个名为 'prototype' 的属性(对象类型),当您在具有原型属性的对象上使用 new 关键字时,它会创建一个引用原型内容的实例并将其存储在您的变量中。所以你在 Javascript 中使用过的所有数组都是 Array 的原型属性的对象和实例。

在任何情况下,尽管数组确实是对象,但由于它们有用的属性和功能(例如长度、切片、推送等),它们的行为类似于数组。

另一个注意事项,虽然我说没有课程,但当你这样做时:

console.log(Object.prototype.toString.call(your_object));

它会给你一个 [object Object] 形式的字符串。但有用的是,当您使用数组调用它时,您会得到 [object Array] 与提供 [object Function] 和许多其他系统定义类型的函数相同的函数,这有助于区分普通对象和数组(因为 typeof运算符将始终只返回字符串 'object')。

试试这个

var a = Array;

然后进入 firebug 并检查 a 的内容,尤其是它的 'prototype' 属性。

编辑:稍微改变了措辞,使其更正确。事实上,当您使用 new 关键字时,它会创建一个引用原型对象的实例。因此,在实例声明之后对原型所做的任何更改,仍然会影响实例。

编辑:回答您最新修订的问题(数组/对象实际上是变相的字符串):不。正如我所解释的,它们是对象。字符串要么是原始类型,要么是对象类型(String 对象的实例),其中包含原始等效项作为其属性之一。

【讨论】:

  • @aiham ... 当您在具有原型属性的对象上使用 new 关键字时,它会创建原型内容的克隆并将它们存储在您的变量中。 i> 这不是真的。原型对象的内容不会被克隆,但创建的实例对象只是对该原型(及其方法)的引用。
  • 我为我的错误措辞道歉。没错,它引用了原型的内容。所以如果在你的实例对象创建后修改原型,实例对象也会受到影响。我会修改我的答案。
  • “所以你曾经在 Javascript 中使用过的所有数组都是 Array 的原型属性的对象和实例。”这是一个引人入胜的声明。
  • 到您的第二次编辑,如果没有原始类型 Object,Objects 与 Javascript 有什么关系?那么它们不会成为内存中的字符串吗?我看不到将字符串、布尔值和整数的原始类型关联起来的方法。这有意义吗?
  • 确实如此。我最近才对 Javascript 原型感兴趣,并且玩弄它真的很有趣。您可以利用对象和原型制作一些非常强大的应用程序。您应该阅读 Douglas Crockford 关于 Javascript (javascript.crockford.com) 的一些内容,其中很多内容非常有用(有些内容有点过头了)。
【解决方案5】:

数组是对象。

但是,与常规对象不同,数组具有某些特殊功能。

  1. 数组的原型链中有一个附加对象 - 即Array.prototype。该对象包含可以在数组实例上调用的所谓数组方法。 (方法列表在这里:http://es5.github.com/#x15.4.4)

  2. 数组有一个 length 属性(它是实时的,因此,它会自动更新)(阅读此处:http://es5.github.com/#x15.4.5.2)

  3. 数组有一个关于定义新属性的特殊算法(阅读这里:http://es5.github.com/#x15.4.5.1)。如果您为数组设置了一个新属性,并且该属性的名称是一个可以强制转换为整数的字符串(如 '1'、'2'、'3' 等),则应用特殊算法(它已定义在规范中的第 123 页)

除了这三样东西,数组就像普通的对象。

阅读规范中的数组:http://es5.github.com/#x15.4

【讨论】:

  • “数组就像普通对象一样”——这很有趣。数组,除了一些装饰它们的方法之外,都是对象,而对象是......?特别是如果关联数组真的只是神奇地“投射”到一个对象中。从这个意义上说,关联数组仍然是数组吗? (如果我对 cast 的使用不正确,我提前道歉。)
  • @Jared 在 JavaScript 中,所有对象都是关联数组。
  • @Šime Vidas - 那么为什么要有一个数组对象呢?我只是想知道,是要公开 .length 属性吗?它们看起来非常相似。
  • @Jared 当成员名称是连续整数时使用数组。当成员名称是任意字符串或名称时使用对象。
  • @Jared 1. JavaScript 不会将数组转换为对象。数组可以包含非索引属性,就像对象一样。事实上,数组可以做常规对象可以做的所有事情(还有更多)。 2. 在 JavaScript 领域中,只存在对象和原始值。只有这两件事。并且对象具有关联数组的特性。 3.顺便说一句,我在JavaScript中找到了一个很好的对象定义:对象是属性的集合。
【解决方案6】:

数组是对象,但具有特殊的性质。对象是由键索引的值的集合(在 Javascript 表示法中,{'key': 'value'}),而数组是键是数字的对象(具有一些函数和属性)。当您使用for each 循环时,它们之间的主要区别是显而易见的——对象将遍历其属性中的所有值,而数组将返回键。 Here's 一个指向 JSFiddle 的链接,展示了差异——请注意,第一个使用数组的 for each 返回索引,而不是值;相反,第二个for each 返回这些键的实际值。

【讨论】:

  • for each 语句只在 Firefox 中实现,我相信。
  • 无论如何,它的示范目的仍然很重要。我可以发誓除了 IE 之外的所有浏览器都支持它,但我可能错了。 :\
  • 是的,我也不确定,但我知道for (var i in obj) 语法得到普遍支持。
【解决方案7】:

在 JavaScript 中有几种类型,everything 其他都是对象。 JavaScript 中的类型有:布尔值、数字和字符串。还有两个特殊值,“null”和“undefined”。

所以“JavaScript 数组是一个对象吗?”这个问题。有点模棱两可。是的,JavaScript 数组是一个“对象”,但它不是“对象”的一个实例。 JavaScript 数组是“Array”的一个实例。虽然,所有对象都继承自 Object;您可以在the MDC 上查看继承链。此外,数组的属性与对象略有不同。数组具有.length 属性。他们还有.slice()、.join()等方法。

Douglas Crockford 提供了一个很好的语言特性survey。他的调查讨论了您所询问的差异。此外,您可以阅读有关问题 #4559207 中的difference between literals and constructors 的更多信息。

【讨论】:

  • 现在看,这符合我的理解。三种类型。但是如何解释Object,其中除了数组之外的其他所有内容都是constructed?我们只是在谈论默认方法原型吗? “是的,JavaScript 数组是一个“对象”,但它不是“对象”的一个实例,这正是我要查询的核心。
  • 是的,Crockford 是 Javascript 被认真对待的原因,IMO。他在 Javascript 前沿组织理智的时间太长了,以至于记不清了(至少从 2004 年开始,更早?)。
  • @Jared 你知道 Crockford 但还没有看过他最基本的 JavaScript 视频系列吗?现在就去看吧! :)
  • @jsummers - 所以数组是具有自定义特殊方法的花哨字符数组?
  • @Šime Vidas - 是的,我知道。克罗克福德是上帝。这里的重点是尽可能多地提取意义,而不是我自己的随机学习过程。我希望有一个对我有意义的意义,那时(谢谢 Thau!)。
猜你喜欢
  • 2012-10-23
  • 1970-01-01
  • 2013-06-19
  • 2017-08-27
  • 2021-08-08
相关资源
最近更新 更多