JavaScript中对象/数组的性能如何?(专门针对Google V8)

JavaScript中对象/数组的性能如何?(专门针对Google V8),javascript,arrays,performance,object,v8,Javascript,Arrays,Performance,Object,V8,JavaScript(特别是Google V8)中与数组和对象相关的性能对于文档来说是非常有趣的。我在互联网上找不到关于这个话题的全面文章 我知道有些对象使用类作为其底层数据结构。如果有很多属性,它有时会被视为哈希表 我也知道数组有时被处理成C++数组(即快速随机索引,缓慢删除和调整大小)。而且,其他时候,它们更像对象(快速索引、快速插入/删除、更多内存)。而且,有时它们可能存储为链表(即缓慢的随机索引,在开始/结束时快速删除/插入) JavaScript中数组/对象检索和操作的精确性能是什么?

JavaScript(特别是Google V8)中与数组和对象相关的性能对于文档来说是非常有趣的。我在互联网上找不到关于这个话题的全面文章

我知道有些对象使用类作为其底层数据结构。如果有很多属性,它有时会被视为哈希表

<>我也知道数组有时被处理成C++数组(即快速随机索引,缓慢删除和调整大小)。而且,其他时候,它们更像对象(快速索引、快速插入/删除、更多内存)。而且,有时它们可能存储为链表(即缓慢的随机索引,在开始/结束时快速删除/插入)

JavaScript中数组/对象检索和操作的精确性能是什么?(专门针对Google V8)

更具体地说,它对性能的影响是什么:

  • 向对象添加属性
  • 从对象中删除属性
  • 为对象中的属性编制索引
  • 向数组中添加项
  • 从数组中删除项
  • 为数组中的项编制索引
  • 正在调用Array.pop()
  • 正在调用Array.push()
  • 正在调用Array.shift()
  • 正在调用Array.unshift()
  • 正在调用Array.slice()
如需了解更多详细信息,欢迎提供文章或链接。:)

编辑:我真的很想知道JavaScript数组和对象在幕后是如何工作的。另外,V8引擎“知道”在什么上下文中“切换”到另一个数据结构

例如,假设我创建了一个带有

var arr = [];
arr[10000000] = 20;
arr.push(21);
这到底是怎么回事

或者。。。这个怎么样

var arr = [];
//Add lots of items
for(var i = 0; i < 1000000; i++)
    arr[i] = Math.random();
//Now I use it like a queue...
for(var i = 0; i < arr.length; i++)
{
    var item = arr[i].shift();
    //Do something with item...
}
var arr=[];
//添加大量项目
对于(变量i=0;i<1000000;i++)
arr[i]=Math.random();
//现在我把它当作一个队列。。。
对于(变量i=0;i

对于传统阵列,性能将非常糟糕;然而,如果使用了LinkedList。。。还不错。

在JavaScript领域的基本层面上,对象的属性是更复杂的实体。您可以使用setter/getter创建具有不同枚举性、可写性和可配置性的属性。数组中的项不能以这种方式进行自定义:它要么存在,要么不存在。在底层引擎级别,这允许在组织表示结构的内存方面进行更多优化

在从对象(字典)识别数组方面,JS引擎总是在两者之间建立明确的界线。这就是为什么有很多文章都在讨论如何制作一个半伪数组状的对象,该对象的行为类似于一个数组,但允许其他功能。这种分离之所以存在,是因为JS引擎本身以不同的方式存储这两者

属性可以存储在数组对象上,但这只是演示了JavaScript如何坚持将所有内容都作为对象。数组中的索引值的存储方式不同于您决定在表示基础数组数据的数组对象上设置的任何属性

每当您使用合法的数组对象并使用操作该数组的标准方法之一时,您都将访问底层数组数据。在V8中,这些基本上与C++数组相同,所以这些规则将适用。如果出于某种原因,您使用的阵列引擎无法确定它是否为阵列,那么您所处的环境将更加不稳定。不过,在V8的最新版本中,还有更多的工作空间。例如,可以创建一个将Array.prototype作为其原型的类,并且仍然可以有效地访问各种本机数组操作方法。但这是最近的变化

指向最近对数组操作所做更改的特定链接可能会在此处派上用场:

另外,这里是直接来自V8源代码的Array Pop和Array Push,它们都是在JS中实现的:

function ArrayPop() {
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined",
                        ["Array.prototype.pop"]);
  }

  var n = TO_UINT32(this.length);
  if (n == 0) {
    this.length = n;
    return;
  }
  n--;
  var value = this[n];
  this.length = n;
  delete this[n];
  return value;
}


function ArrayPush() {
  if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
    throw MakeTypeError("called_on_null_or_undefined",
                        ["Array.prototype.push"]);
  }

  var n = TO_UINT32(this.length);
  var m = %_ArgumentsLength();
  for (var i = 0; i < m; i++) {
    this[i+n] = %_Arguments(i);
  }
  this.length = n + m;
  return this.length;
}
函数ArrayPop(){
如果(是空的或未定义的(此)&!是不可检测的(此)){
抛出MakeTypeError(“在\u null\u上调用\u或\u未定义”,
[“Array.prototype.pop”];
}
var n=至_UINT32(该长度);
如果(n==0){
这个长度=n;
返回;
}
n--;
var值=此[n];
这个长度=n;
删除此[n];
返回值;
}
函数ArrayPush(){
如果(是空的或未定义的(此)&!是不可检测的(此)){
抛出MakeTypeError(“在\u null\u上调用\u或\u未定义”,
[“Array.prototype.push”];
}
var n=至_UINT32(该长度);
var m=%_ArgumentsLength();
对于(变量i=0;i
我创建了()

从这个意义上讲,您可以在这个50多个测试用例测试仪中看到性能问题(这将需要很长时间)

顾名思义,它还探讨了使用DOM结构的本机链表特性的用法

总结如下

  • V8阵列速度很快,非常快
  • 阵列推/跳/移速度比任何等效对象快约20倍以上
  • 令人惊讶的是,
    Array.shift()
    比数组pop快约6倍,但比对象属性删除快约100倍
  • 有趣的是,
    Array.push(数据)
    Array[nextIndex]=data
    快近20倍(动态数组)到10倍(固定数组)
  • Array.unshift(data)
    与预期一样慢,并且比添加新属性慢约5倍
  • 将值
    array[index]=null设置为null要比将其删除快
    delete a
    
    16: 4ms
    40: 8ms 2.5
    76: 20ms 1.9
    130: 31ms 1.7105263157894737
    211: 14ms 1.623076923076923
    332: 55ms 1.5734597156398105
    514: 44ms 1.5481927710843373
    787: 61ms 1.5311284046692606
    1196: 138ms 1.5196950444726811
    1810: 139ms 1.5133779264214047
    2731: 299ms 1.5088397790055248
    4112: 341ms 1.5056755767118273
    6184: 681ms 1.5038910505836576
    9292: 1324ms 1.5025873221216042
    
    126: 284ms
    254: 65ms 2.015873015873016
    510: 28ms 2.0078740157480315
    1022: 58ms 2.003921568627451
    2046: 89ms 2.0019569471624266
    4094: 191ms 2.0009775171065494
    8190: 364ms 2.0004885197850513
    
    256: 11ms 256
    512: 26ms 2
    1024: 77ms 2
    1708: 113ms 1.66796875
    2848: 154ms 1.6674473067915691
    4748: 423ms 1.6671348314606742
    7916: 944ms 1.6672283066554338
    
    var arrayCount = 10000;
    
    var dynamicArrays = [];
    
    for(var j=0;j<arrayCount;j++)
        dynamicArrays[j] = [];
    
    var lastLongI = 1;
    
    for(var i=0;i<10000;i++)
    {
        var before = Date.now();
        for(var j=0;j<arrayCount;j++)
            dynamicArrays[j][i] = i;
        var span = Date.now() - before;
        if (span > 10)
        {
          console.log(i + ": " + span + "ms" + " " + (i / lastLongI));
          lastLongI = i;
        }
    }