40

即,以下代码如何:

var sup = new Array(5);
sup[0] = 'z3ero';
sup[1] = 'o3ne';
sup[4] = 'f3our';
document.write(sup.length + "<br />");

当你所做的只是设置各种元素时,输出'5'的长度?

length这段代码的“问题”是,如果不调用 agetLength()或方法,我不明白如何更改setLength()。当我执行以下任何操作时:

a.length
a['length']
a.length = 4
a['length'] = 5

在非数组对象上,它的行为类似于 dict / 关联数组。当我对数组对象执行此操作时,它具有特殊含义。JavaScript 中的什么机制允许这种情况发生?JavaScript 是否有某种类型的属性系统可以翻译

a.length
a['length']

进入“get”方法和

a.length = 4
a['length'] = 5

进入“设置”方法?

4

8 回答 8

24

JavaScript 中的一切都是对象。在 的情况下Array,该length属性返回数组索引项的内部存储区域的大小。一些混淆可能会出现,因为[]运算符适用于数字和字符串参数。对于数组,如果将其与数字索引一起使用,它将返回/设置预期的索引项。如果将它与字符串一起使用,它会返回/设置数组对象上的命名属性 - 除非字符串对应于数值,否则它会返回索引项。这是因为在 JavaScript 中,数组索引是通过隐式toString()调用强制转换为字符串的。坦率地说,这只是让你挠头说“JavaScript,这,这就是他们嘲笑你的原因”的另一件事。

浏览器之间的实际底层表示可能不同(也可能不同)。除了使用它时提供的接口之外,我不会依赖任何其他东西。

你可以在 MDN找到更多关于 JavaScript 数组的信息。

于 2008-12-14T00:41:12.447 回答
5

JavaScript 数组的特征

  1. 动态 - JavaScript 中的数组可以动态增长 .push
  2. 可以是稀疏的 - 例如,array[50000] = 2;
  3. 可以是密集的 - 例如,array = [1, 2, 3, 4, 5]

在 JavaScript 中,运行时很难知道数组是密集的还是稀疏的。所以它所能做的就是猜测。所有实现都使用启发式方法来确定数组是密集的还是稀疏的。

例如,上面第 2 点中的代码可以向 JavaScript 运行时指示这可能是一个稀疏数组实现。如果数组是用初始计数初始化的,这可能表明这可能是一个密集数组。

当运行时检测到数组是sparse时,它​​的实现方式与对象类似。因此,与其维护一个连续的数组,不如构建一个键/值映射。

有关更多参考,请参阅JavaScript 数组是如何在内部实现的?

于 2019-05-25T11:37:18.777 回答
4

这真的取决于你打算用它做什么。

[].length是“神奇的”。
它实际上并不返回数组中的项目数。它返回数组中最大的 instated 索引。

var testArr = [];  testArr[5000] = "something";  testArr.length; // 5001

但是 setter 背后的方法隐藏在引擎本身中。
某些浏览器中的某些引擎将使您能够访问它们对这些魔术方法的实现。其他人将完全锁定所有内容。

所以不要依赖 defineGetter 和 defineSetter 方法,甚至,真的,__proto__方法,除非你知道你知道你的目标是哪些浏览器,而你不是。

这将在未来发生变化,使用 ECMAScript Next/6 编写的选择加入应用程序将可以访问更多。

兼容 ECMAScript 5 的浏览器已经开始在对象中提供魔术方法,get而且set还会有更多……但是可能还需要一段时间才能放弃对 oldIE 和大量智能手机等的支持……

于 2012-07-22T23:11:51.683 回答
2

重要的是要知道,当您这样做时,sup['look'] = 4;您不是在使用关联数组,而是在修改 object 的属性sup

这相当于sup.look = 4;因为您可以随时在 JavaScript 对象上动态添加属性。sup['length']将在您的第一个示例中输出 5 。

于 2008-12-14T00:35:41.350 回答
2

添加到tvanfosson 的答案:在 ECMA-262(我相信是 3.0 规范)中,数组被简单地定义为具有这种设置属性的行为(参见 15.4.5.1)。它没有底层的通用机制(至少到目前为止)——这就是它的定义方式,以及 JavaScript 解释器必须如何运行。

于 2008-12-14T04:07:20.797 回答
2

正如其他人所提到的,JavaScript 中的属性基本上可以充当数组(或字符串或其他输入)的 getter 和 setter。

事实上,你可以自己试试这个:

const test = [1, 2, 3, 4, 5]
test.length = 3
console.log(test) // [1, 2, 3]
test.length = 5
console.log(test) // Guess what happens here!

据我所知,JavaScript 中的数组与关联数组的工作方式并不完全相同,并且您可以将元素尽可能连续地放入内存中(假设您可以拥有混合对象的数组),具体取决于您正在考虑的 JavaScript 引擎。

作为旁注,我有点困惑的是,投票最多的答案一直在传播“一切都是 JavaScript 中的对象”的过于简单的神话(或半真半假);这并不完全正确,否则您将永远不会学习原语,例如。

尝试这样做:

const pippi = "pippi"
pippi.cat = "cat"
console.log(pippi.cat) // Will it work? Throw an error? Guess why again

剧透:字符串被包装在第二行的特定操作的一次性对象中,然后在接下来的一个中,您将访问不存在的原语的属性(前提是您没有玩过String.prototype或类似的东西) ),所以你得到undefined.

于 2019-01-26T19:33:57.133 回答
1

Array对象从 继承callerconstructorlengthname属性Function.prototype

于 2008-12-14T01:17:56.910 回答
0

JavaScript 数组是一个对象,就像任何其他对象一样,但 JavaScript 赋予了它特殊的语法。

arr[5] = "yo"

以上是语法

arr.insert(5,"yo")

这就是您将东西添加到常规对象的方式。改变 arr.length 值的是insert方法内部的内容

在此处查看我对 customArray 类型的实现:http: //jsfiddle.net/vfm3vkxy/4/

于 2015-03-21T00:26:46.677 回答