该帖已经被评为隐藏帖
|
|
---|---|
作者 | 正文 |
发表时间:2007-02-06
孙向晖 sunshineormer at hotmail.com map是JSObject的一个重要属性,存放一个对象的所有的属性的入口。要想了解map,就需要打开jsobj.h文件,看里面的定义。 struct JSObject { JSObjectMap *map; jsval *slots; }; <o:p> </o:p> 很自然的,我们还要找到JSObjectMap的定义,它也在jsobj.h文件中 struct JSObjectMap { jsrefcount nrefs; /* count of all referencing objects */ JSObjectOps *ops; /* high level object operation vtable */ uint32 nslots; /* length of obj->slots vector */ uint32 freeslot; /* index of next free obj->slots element */ }; 在这个定义中,最重要的信息隐含在注释中,第一个是对ops的注释,我们会看到ops其实是一个virtual table。这表示,对象的所有的属性名,都存放在这个vtable中;第2个信息是对nslots的注释,它提及obj->slots其实是一个vector。 这如同在告诉我们,我们在定义一个对象的属性时,属性的名称和类型等信息,会通过ops增加到属性表中,属性的值会对应放到slots这个vector中。例如: var obj = new Object(); obj.a = 5; 那么“a”这个属性的类型是整型的,slots中增加了个新的值5。仔细看去,ops是JSObjectOps这个结构体中,我们可以在jsapi.h中找到这个结构体的定义: struct JSObjectOps { /* Mandatory non-null function pointer members. */ JSNewObjectMapOp newObjectMap; JSObjectMapOp destroyObjectMap; JSLookupPropOp lookupProperty; JSDefinePropOp defineProperty; JSPropertyIdOp getProperty;<o:p></o:p> JSPropertyIdOp setProperty; JSAttributesOp getAttributes; JSAttributesOp setAttributes; JSPropertyIdOp deleteProperty; JSConvertOp defaultValue; JSNewEnumerateOp enumerate; JSCheckAccessIdOp checkAccess; <o:p> </o:p> /* Optionally non-null members start here. */ JSObjectOp thisObject; JSPropertyRefOp dropProperty; JSNative call; JSNative construct; JSXDRObjectOp xdrObject; JSHasInstanceOp hasInstance; JSSetObjectSlotOp setProto; JSSetObjectSlotOp setParent; JSMarkOp mark; JSFinalizeOp clear; JSGetRequiredSlotOp getRequiredSlot; JSSetRequiredSlotOp setRequiredSlot; }; <o:p> </o:p> 我们可以简单的浏览一下其中的函数指针名称,创建object的map,定义属性,删除属性,给属性设置值或者获取属性值。。。。闭上眼睛想一想,这其中的函数指针是如此之多,所以一个对象的属性的类型判断(比如是整型还是String还是其他的)或者是属性名或者属性值的存放,都是通过预先定义好的指针函数来完成。 我们甚至可以用一个新的示意图来表示这一切: <o:p> </o:p> <v:shapetype id="_x0000_t75" stroked="f" filled="f" path="m@4@5l@4@11@9@11@9@5xe" o:preferrelative="t" o:spt="75" coordsize="21600,21600"><v:stroke joinstyle="miter"></v:stroke><v:formulas><v:f eqn="if lineDrawn pixelLineWidth 0"></v:f><v:f eqn="sum @0 1 0"></v:f><v:f eqn="sum 0 0 @1"></v:f><v:f eqn="prod @2 1 2"></v:f><v:f eqn="prod @3 21600 pixelWidth"></v:f><v:f eqn="prod @3 21600 pixelHeight"></v:f><v:f eqn="sum @0 0 1"></v:f><v:f eqn="prod @6 1 2"></v:f><v:f eqn="prod @7 21600 pixelWidth"></v:f><v:f eqn="sum @8 21600 0"></v:f><v:f eqn="prod @7 21600 pixelHeight"></v:f><v:f eqn="sum @10 21600 0"></v:f></v:formulas><v:path o:connecttype="rect" gradientshapeok="t" o:extrusionok="f"></v:path><o:lock aspectratio="t" v:ext="edit"></o:lock></v:shapetype><v:shape id="_x0000_i1025" style="WIDTH: 213.75pt; HEIGHT: 131.25pt" type="#_x0000_t75"><v:imagedata o:title="" src="file:///C:\DOCUME~1\ADMINI~1\LOCALS~1\Temp\msohtml1\01\clip_image001.png"></v:imagedata></v:shape> 我们可以这样去想,有一个table,里面存放对象的属性列表。根据ruby hacking guide的说法,我们可以想像,有一张大的表,存放所有的对象的属性,也可能每个对象有自己的属性表。但,这属于具体实现的范畴,我们只要明白每个对象有属于自己的属性表,对表格中的行或者列进行操作时,是由JSObjectOps这个结构体中的指针函数来完成的就可以了。 /* * Share proto's map only if it has the same JSObjectOps, and only if * proto's class has the same private and reserved slots as obj's map * and class have. We assume that if prototype and object are of the * same class, they always have the same number of computed reserved * slots (returned via clasp->reserveSlots); otherwise, prototype and * object classes must have the same (null or not) reserveSlots hook. */ if (proto && (map = proto->map)->ops == ops && ((protoclasp = OBJ_GET_CLASS(cx, proto)) == clasp || (!((protoclasp->flags ^ clasp->flags) & (JSCLASS_HAS_PRIVATE | (JSCLASS_RESERVED_SLOTS_MASK << JSCLASS_RESERVED_SLOTS_SHIFT))) && protoclasp->reserveSlots == clasp->reserveSlots))) { /* * Default parent to the parent of the prototype, which was set from * the parent of the prototype's constructor. */ if (!parent) parent = OBJ_GET_PARENT(cx, proto); <o:p> </o:p> /* Share the given prototype's map. */ obj->map = js_HoldObjectMap(cx, map); <o:p> </o:p> /* Ensure that obj starts with the minimum slots for clasp. */ nslots = JS_INITIAL_NSLOTS; } else { /* Leave parent alone. Allocate a new map for obj. */ map = ops->newObjectMap(cx, 1, ops, clasp, obj); if (!map) goto bad; obj->map = map; <o:p> </o:p> /* Let ops->newObjectMap set nslots so as to reserve slots. */ nslots = map->nslots; } Ok,我们在上回书说到有若干的判断条件,就是为了创建一个map,并设置为obj->map的属性――不管是用parent的原型来创建,还是单独创建新的map(if 。。。else 部分),最终都是为了这个目的。 <o:p> </o:p> /* Allocate a slots vector, with a -1'st element telling its length. */ newslots = AllocSlots(cx, NULL, nslots); if (!newslots) { js_DropObjectMap(cx, obj->map, obj); obj->map = NULL; goto bad; } <o:p> </o:p> /* Set the proto, parent, and class properties. */ newslots[JSSLOT_PROTO] = OBJECT_TO_JSVAL(proto); newslots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(parent); newslots[JSSLOT_CLASS] = PRIVATE_TO_JSVAL(clasp); <o:p> </o:p> /* Clear above JSSLOT_CLASS so the GC doesn't load uninitialized memory. */ for (i = JSSLOT_CLASS + 1; i < nslots; i++) newslots[i] = JSVAL_VOID; 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
浏览 1448 次