JavaScript数组的内存管理

JavaScript数组的内存管理,javascript,arrays,memory,memory-management,Javascript,Arrays,Memory,Memory Management,可能重复: 目前我正在学习JavaScript,并阅读了一些简单的介绍和教程。在查看数组对象时,我偶然发现了一些细节,这些细节来自其他语言,比如C/Java/Scala/ 因此,假设我们将数组定义为: var arr = ['foo','bar','qux'] 我们现在分配 arr[5] = 'baz' 这导致我们的阵列如下所示: arr >> ["foo", "bar", "qux", undefined, undefined, "baz"] 长度与预期一致 arr.le

可能重复:

目前我正在学习JavaScript,并阅读了一些简单的介绍和教程。在查看数组对象时,我偶然发现了一些细节,这些细节来自其他语言,比如C/Java/Scala/


因此,假设我们将数组定义为:

var arr = ['foo','bar','qux']
我们现在分配

arr[5] = 'baz'
这导致我们的阵列如下所示:

arr
>> ["foo", "bar", "qux", undefined, undefined, "baz"]
长度与预期一致

arr.length
>> 6

JavaScript已经将我们的数组扩展到所需的长度-六个-并且新的项被设置为未定义-除了我们实际分配了一个值的项

从低级的角度来看,这是可怕的记忆。通常,数组在内存中是一个连续的范围-使数组变大通常需要将整个数组复制到一个新的内存位置,使其足够大。这是一个非常昂贵的操作

现在,我确实意识到这可能是而不是JavaScript引擎正在做的事情,因为围绕数组进行复制会非常昂贵,而且内存空间会浪费在所有这些“未定义”的值上

有人能告诉我门后到底发生了什么吗

  • 数组实际上是某种排序链表吗
  • “未定义”数组项是否实际存在
  • 使用大型阵列(这些阵列大部分都是“未定义的”)的成本有多高

数组只是一个有序的对象列表在JavaScript中,一切都是一个对象,因此数组并不是我们所知道的真正的数组:)

你可以找到一些内部的东西

对于您对使用大型阵列的疑虑。。。好的,记住,“客户端”的计算越少,你的页面就会越快。

答案:

  • JavaScript中的数组与对象(即无序的属性集合)完全相同,具有神奇的
    length
    属性和额外的原型方法(
    push()
    等)
  • 不,未定义的项不存在。JavaScript在操作符中有一个
    ,用于测试是否存在可以用来证明这一点的属性。因此对于以下数组:
    var arr=['foo'];arr[2]=‘bar’,arr中的
    2返回
    true
    ,arr中的
    1返回
    false
  • 稀疏数组不应比密集数组占用更多内存,密集数组的长度是稀疏数组中实际定义的属性数。当您迭代稀疏数组的未定义属性时,使用稀疏数组的成本只会更高

  • 在JavaScript的第一个版本中,没有数组。它们后来被作为“所有对象之母”的一个子类引入:
    Object
    。通过执行以下操作,您可以非常轻松地进行测试:

    var foo = [1,2,3,4];
    for (var n in foo)
    {//check if n is equal (value and type) to itself, coerced to a number
        console.log(n === +(n) ? 'Number' : 'String');
    }
    
    这将一次又一次地记录字符串。在内部,所有数字键都转换为字符串。Length属性仅获取最高索引,并向其添加1。没别的了。当显示数组时,对象将被迭代,对于每个键,应用与任何对象相同的规则:首先扫描实例,然后扫描原型。。。因此,如果我们稍微修改一下代码:

    var foo = [1,2,3,4];
    foo[9] = 5;
    for (var n in foo)
    {
        if (foo.hasOwnProperty(n))
        {//check if current key is an array property
            console.log(n === +(n) ? 'Number' : 'String');
        }
    }
    
    您会注意到该数组只有5个自己的属性,
    undefined
    键4-8是未定义的,因为在实例中或任何基础原型中都找不到相应的值。简言之:数组不是真正的数组,而是行为类似的对象

    正如Tim所说,您可以拥有一个具有未定义属性的数组实例,该属性确实存在于该对象中:

    var foo = [1,2,undefined,3];
    console.log(foo[2] === undefined);//true
    console.log(foo[99] === undefined);//true
    
    但是,这里又有一个区别:

    console.log((foo.hasOwnProperty('2') && foo[2] === undefined));//true
    console.log((foo.hasOwnProperty('99') && foo[99] === undefined));//false
    
    总结一下你的三个主要问题:

    • 数组是对象,允许您使用数值实例引用其属性

    • 未定义的
      值不存在,它们只是JS扫描对象和原型时的默认返回值,无法找到您要查找的内容:“对不起,您问我的问题在我的书中未定义。”就是它所说的

    • 使用大量未定义的数组不会影响对象本身的大小,但是访问未定义的键可能会非常非常缓慢,因为原型也必须扫描
    更新:

    只是:

    15.4数组对象
    数组对象对某类属性名给予特殊处理。属性名称P(以 字符串值)是数组索引,当且仅当ToString(ToUint32(P))等于P且ToUint32(P)不等于 2^32 1.属性名为数组索引的属性也称为元素。每个数组对象都有一个 长度属性,其值始终为小于2^32的非负整数。长度的值 属性的数值大于名称为数组索引的每个属性的名称;每当 创建或更改数组对象的属性时,将根据需要调整其他属性以保持此属性 不变的具体来说,每当添加名称为数组索引的属性时,length属性都是 如有必要,更改为比该数组索引的数值多一个;只要长度 属性,每个名称为数组索引且其值不小于新值的属性 长度将自动删除。此约束仅适用于阵列对象的自身属性,并且是 不受可能从原型继承的长度或数组索引属性的影响

    如果以下算法返回true,则称对象O为稀疏对象:
    1.让len作为调用带有参数“length”的O的[[Get]]内部方法的结果。
    2.对于0范围内的每个整数i≤我
    a。让elem成为调用带有参数的O的[[GetOwnProperty]]内部方法的结果 ToString(i)。
    b。如果元素未定义,则返回true。
    3.返回fal