大家都知道对象是key-value的形式,查询效率是O(1),字典底层结构是哈希数组,那么在v8中怎么处理这个key-value形式的对象存储呢?
在v8中,对象的属性分为快属性和慢属性。
什么是快属性,什么是慢属性
var obj = {};
obj[1] = 'el1';
obj[3] = 'el3';
obj[2] = 'el2';
obj['p1'] = 'pp1';
obj['p3'] = 'pp3';
obj['p2'] = 'pp2';
for (var key in obj) {
console.log(key);
}
上面的代码的结果可以看出,如果属性索引是数字,那么查找的时候会按照数字顺序查找,如果属性索引是字符串,那么查找的时候会按照先到先出的顺序查找,并且遍历的时候先遍历属性索引是数字的属性,后遍历属性索引是字符串的属性。
现象就是上面的现象,那么v8是怎么区分的呢?
假设现在我们有下面的Foo
构造函数
打开Chrome,在Memory拍一下当前页面的快照,可以看出Foo是分为elements和properties两个内容,其中elements是存储数字索引的属性,properties是存储字符串索引的属性。
先来看看elements
var h = new Foo(10, 0);
我们先不设置字符串索引属性,可以看到,除了在elements中存放数据,还在第一层有同样的数据。实际上第一层的数据只是一个指向elements中对应数据的一个引用,如下图所示
对比外层和内层的[1],他们实际上是同一个东西,在外层放一个引用是为了在查找的时候能减少一步elements的查询。可以看到下面的Distance内层的是3,外层的是2。
在elements的存储中,默认是顺序存储,那么查询的效率就是O(1)。
h[111] = 'ele111';
如果我们执行以上的代码,会发生什么呢?
elements中似乎变成了不是按照顺序存储了,这个时候是一个稀疏数组,如果按照顺序存储会导致大量的空间浪费。这个例子看不出来多大的变化,再看下面的例子。
var i = new Foo(1000, 0);
可以看出已经不是按照数字的顺序进行排序了,实际上当elements中的数量大于等于20个的时候,存储的方式变成了哈希表,变为哈希表相对于稀疏数组节省了大量空间,同时理论上也能做到O(1)的查询效率。
再看看properties
properties跟elements类似,都是在空间和时间中作出最好的查询方案。
var j = new Foo(0, 10);
当properties的数量不大于10的时候,全部properties直接放在第一层中,减少一层的查询,提升效率。
var k = new Foo(0, 13);
当properties的数量大于10并且不大于30的时候,前10个属性同样放在外层,剩下的属性放在properties,使用数组存储,在不多数据的情况下查询速度可观。外层通过引用的形式指向内部对应的属性。
var l = new Foo(0, 30);
当properties的数量大于30的时候,properties变得毫无顺序可言,实际上存储方式已经变成了哈希表。这是因为数据量多的时候,链表的查询速度会越来越慢,所以变成了哈希表支持更快的查询
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。