Javascript 数组是原语吗?字符串?对象?

IT技术 javascript arrays javascript-objects
2021-02-03 18:57:37

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

我一直认为 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 文字、原语和字符串/对象/数组/等,我需要了解什么?

数组/对象只是伪装的字符串吗?为什么/为什么不?他们以什么方式(这样/不)?

6个回答

数组是对象。

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

  1. 数组在其原型链中有一个额外的对象——即Array.prototype. 这个对象包含所谓的 Array 方法,可以在数组实例上调用。(方法列表在这里: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

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

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

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

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

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

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

var str = 'yes';

给你一个原始的,而,

var str = new String('yes');

会给你一个 String 对象。


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

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

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

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

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

试试这个

var a = Array;

并进入萤火虫并检查 a 的内容,尤其是它的“原型”属性。

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

编辑:回答您最新修订的问题(数组/对象实际上是伪装的字符串):不。正如我所解释的,它们是对象。字符串要么是基本类型,要么是对象类型(字符串对象的一个​​实例),其中包含基本等价物作为其属性之一。

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

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

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

混淆来自这样一个事实,即 javascripts 允许您通过两种方式访问​​对象属性:

myObj.attribute 或 myObj["attribute"]

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

这与 Javascript 中的对象有什么不同吗?
2021-03-13 18:57:37
“真正使数组成为数组的原因与您存储数据的方式无关” - 我喜欢这个答案只是因为它回答了我对为什么对象/数组在 JS 中令人困惑的想法。
2021-03-13 18:57:37
@The Scrum Master 很确定这就是人们说通过引用传递时的意思......对吗?
2021-03-29 18:57:37
更正:数组的引用是按值传递的。
2021-03-30 18:57:37

试图简要介绍我认为最重要的内容:数组具有许多对象没有的方法。包括:

  • 长度
  • 流行音乐

声明为的对象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']=xfoo.bar=y喜欢一个对象,但不一定可以像上面突出显示的那样循环遍历。

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

@slifty:确实如此。数组文字是我上面提到的对象。继承自 Array 原型方法的数组,例如 length push 和 pop,纯对象字面量不存在这些方法
2021-03-14 18:57:37
@Šime Vidas:确实,但var foo=[0,1]; foo.bar=2; for(var i=0;i<foo.length;i++){console.log(foo[i]);}对于新手 javascript 开发人员来说不会按预期工作
2021-04-04 18:57:37
小心连接。数组具有这些方法,因为它们是对象,其原型已被赋予这些功能。
2021-04-06 18:57:37
@connrs 不是真的。数组可以像任何其他对象一样具有属性:var arr = []; arr.foo = 'Totally fine!';
2021-04-08 18:57:37
@connrs 在您的回答中,您说这是无效的:foo['bar'] = 'totallyinvalid';但事实并非如此。这是有效的。这就是我的观点。
2021-04-08 18:57:37