看到这个题目,可能有人会觉得奇怪——Object不是JS的基本数据类型吗?有没有实现不了的?如果你这么认为,那说明你还没有接触过其他语言,一直和JS打交道。编程世界那么大,你没有出去看看。C/C++/Java等语言没有这个json数据类型。其他人这样做:例如,它在Pthyon中称为字典,在Ruby/Perl中称为哈希表。当然这只是一个名字,可以作为json类型使用。而C是“万物之母”,C中没有的东西必须通过一定的方式实现。而JS中的Object是如何找到属性的呢?有人说是遍历key的字符串查找,也有人说是hash查找。它是如何存储和搜索的?Object可以用作地图吗?如果你不能真正从源码的角度去看待浏览器的实现,你的观点可能站不住脚,只能听从别人的意见。Chrome开发了自己的V8引擎,Node将其用作解析器。本文将尝试通过V8的源码来分析Object的实现。一、V8的代码结构V8的源代码位于src/v8/src/,代码层次比较简单,但是实现比较复杂。为了理解它,需要找到一个入口点,并通过断点和添加日志的方式来确定这个。入口点是正确的。如果这个点不是关键点,会在某一步断掉,那就从这个点开始,再尝试寻找其他点。不断验证,最后找到最关键的地方,从这个地方由浅入深扩展到其他地方,最终形成一个体系。下面先介绍JSObject的类图。2、JSObject类图V8中所有数据类型的根父类都是Object。Object派生HeapObject提供基本的存储功能。下面的JSReceiver是用来做原型查找的,下面的JSObject就是JS中的Object和Array。/Function/Date等继承自JSObject。左边的FixedArray是实际存储数据的地方。3、创建JSObject在创建JSObject之前,首先会将读取到的Object的文本属性序列化为constant_properties,如下数据:vardata={name:"yin",age:18,"-school-":"highschool"};将被排序为:../../v8/src/runtime/runtime-literals.cc72constant_properties:0xdf9ed2aed19:[FixedArray]–length:6[0]:0x1b5ec69833d1[1]:0xdf9ed2aec51[2]:0xdf9ed2aec71[3]:18[4]:0xdf9ed2aec91[5]:0xdf9ed2aecb1是一个FixedArray,共有6个元素。由于data一共有3个属性,每个属性都有key和value,所以有6个Array。第一个元素是第一个键,第二个元素是第一个值,第三个元素是第二个键,第四个元素是第二个键,依此类推。Object提供了一个Print()函数,对于打印对象信息很有帮助。上面输出的数据有两种,一种是String类型,一种是整型。FixedArray是V8实现的类数组类。它代表了一个连续的记忆。上面FixedArray的长度=6,那么它占用的内存大小会是:length*kPointerSize因为它存放的是对象指针(或者直接是整型数据类型,比如上面的18。在64位操作系统上,一个指针是8个字节,它的大小将是48个字节,它记录了一个初始内存起始地址,用元素索引乘以指针大小作为偏移量,加上起始地址,就可以得到对应索引的元素,和数组一样,只是V8自己封装了一个,方便添加一些自定义的功能,FixedArray主要用来表示数据的存储位置,上面还有一个Map,就是用来表示数据的结构,这里的Map并不是hash的意思,而是更接近map的意思,用来操作FixedArray所代表的内存。V8根据constant_properties的长度,开辟一个对应大小的Map:Handlemap=ComputeObjectLiteralMap(context,constant_properties,&is_result_from_cache);打印出应用的Map:../../v8/src/heap/heap.cc3472mapis0x21528af9cb39:[Map]–type:JS_OBJECT_TYPE–instancesize:48–inobjectproperties:3–backpointer:0x3e2ca8902311–instancedescriptors(own)#0:0x3e2ca8902231从第4行的粗体可以看出,它的大小确实和我们计算的一样。而且它还有一个叫做描述符的数据结构来表示它。描述符记录了每个键值对及其在FixedArray中的索引。后续对属性的操作基本都是通过描述符进行的。有了这个地图对象之后,用它来创建一个JSObect:Handleboilerplate=isolate->factory()->NewJSObjectFromMap(map,pretenure_flag);重新开一段内存,复制地图的内容。由于map只是一块相应大小的内存空间,内容为空,所以接下来要设置它的属性:for(intindex=0;indexkey(constant_properties->get(index+0));Handle