banner.gif adie's blog
主页 博客 胭脂泪,相留醉,几时重,自是人生长恨水长东
统计
日志总数: 128
评论总数: 123
日志分类
日志归档
最近日志
最近评论
订阅
rss2.gif

atom.gif

google_rss
zt.gif 【技术资料】 阅读 5165 次

javascript hacking guide part 5

2007-03-26 12:38:13
[摘自] sunshineormer.javaeye.com

map是JSObject的一个重要属性,存放一个对象的所有的属性的入口。要想了解map,就需要打开jsobj.h文件,看里面的定义。

struct JSObject {

    JSObjectMap *map;

    jsval       *slots;

};

 

很自然的,我们还要找到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;

    JSPropertyIdOp      setProperty;

    JSAttributesOp      getAttributes;

    JSAttributesOp      setAttributes;

    JSPropertyIdOp      deleteProperty;

    JSConvertOp         defaultValue;

    JSNewEnumerateOp    enumerate;

    JSCheckAccessIdOp   checkAccess;

 

    /* 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;

};

 

我们可以简单的浏览一下其中的函数指针名称,创建object的map,定义属性,删除属性,给属性设置值或者获取属性值。。。。闭上眼睛想一想,这其中的函数指针是如此之多,所以一个对象的属性的类型判断(比如是整型还是String还是其他的)或者是属性名或者属性值的存放,都是通过预先定义好的指针函数来完成。

我们甚至可以用一个新的示意图来表示这一切:

 


我们可以这样去想,有一个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);

 

        /* Share the given prototype's map. */

        obj->map = js_HoldObjectMap(cx, map);

 

        /* 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;

 

        /* Let ops->newObjectMap set nslots so as to reserve slots. */

        nslots = map->nslots;

    }

Ok,我们在上回书说到有若干的判断条件,就是为了创建一个map,并设置为obj->map的属性――不管是用parent的原型来创建,还是单独创建新的map(if 。。。else 部分),最终都是为了这个目的。

 

/* 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;

    }

 

    /* 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);

 

    /* Clear above JSSLOT_CLASS so the GC doesn't load uninitialized memory. */

    for (i = JSSLOT_CLASS + 1; i < nslots; i++)

        newslots[i] = JSVAL_VOID;

BORDER-RIGHT: medium none; PADDING-RIGHT: 0cm; BORDER-TOP: medium none; PADDING-LEFT: 0cm; BACKGROUND: silver;

▲评论

› 网友 adie () 于 2007-03-25 23:40:17 发表评论说:
示意图: http://album.sina.com.cn/pic/471b15db02000pqx
X 正在回复:
姓 名: 留下更多信息
性 别:
邮 件:
主 页:
Q Q:
来 自:
职 业:
评 论:
验 证:


Valid HTML 4.01 Strict Valid CSS!
Copyleft.A!die Software Studio.ADSS
Power by webmaster@adintr.com