[领域]javascript hacking guide part 6

书接上回,我们说到global对象的初始创建已经完成了。那,你肯定会问了,为什么说是初始创建,而不是完整的创建呢?要回答这个问题,还要从ECMA262说起:

ECMA262,强调了Global这个全局函数的很多信息,比如说,这个内置对象是先于Context就存在了的。比方说,在默认的情况下,我们调用的方法,其实都是Global这个对象的方法。比方说

var obj = new Object();

其实也就等于

var obj = new this.Object();

parseInt这样的方法,其实也都是挂在Global名下的。Global对象下,有若干属性,包括Object,Array,Boolean,String…. 这么说你肯定就明白了。其他的内置对象,都是Global的一个属性值。其实,不光内置对象,所有的新定义的function ,也都会在定义后(即通过function关键字)在Global的属性列表中增加一个指向自己的属性。

那么,我们可以想一下,GlobalObject之间的关系,真的是很微妙啊。Global.prototypeObject.prototype会是什么样的关系呢?

如果你是一个心急的人,一点会说:“写一段代码不就知道了吗?”。你的程序是不是这样写的?

document.writeln(global.prototype = = …

sorry,忘了告诉你了,global对象是不能这么访问的。你在程序中写:

document.writeln(global);

将会打出undefined.不过,这个Global对象又缺省存在,我们应该怎么去访问它呢?请让我先卖一个关子吧。

有了Global的这个概念以后,我们继续来分析源代码。从part4part5,我们基本上只在围绕着一个函数做文章,

glob = JS_NewObject(cx, &global_class, NULL, NULL);

这个函数的调用关系讲完之后,我们就要看下面的代码段了。

JS_InitStandardClasses(cx, glob)

JS_DefineFunctions(cx, glob, shell_functions)

从名字上看,我们是要在glob这个对象下,创建并挂接系统内置的对象了(事实也果真如此)。

JS_InitStandardClasses这个函数定义在jsapi.c 这个文件中,我们可以很容易的找到其中的重要部分:

/* Define a top-level property 'undefined' with the undefined value. */

atom = cx->runtime->atomState.typeAtoms[JSTYPE_VOID];

if (!OBJ_DEFINE_PROPERTY(cx, obj, ATOM_TO_JSID(atom), JSVAL_VOID,

NULL, NULL, JSPROP_PERMANENT, NULL)) {

return JS_FALSE;

}

/* Function and Object require cooperative bootstrapping magic. */

if (!js_InitFunctionAndObjectClasses(cx, obj))

return JS_FALSE;

/* Initialize the rest of the standard objects and functions. */

return js_InitArrayClass(cx, obj) &&

js_InitBlockClass(cx, obj) &&

js_InitBooleanClass(cx, obj) &&

js_InitCallClass(cx, obj) &&

js_InitExceptionClasses(cx, obj) &&

js_InitMathClass(cx, obj) &&

。。。。

我在这段代码中,找到的几个处比较重要的函数调用,用红颜色圈了出来。

第一个部分是一个宏:OBJ_DEFINE_PROPERTY这个宏的主要作用是调用函数指针,来给glob对象创建一个新的属性,属性的类型是JSVAL_VOID,这说明,ECMA262中要求的,Undefined属性是Global的一个属性,已经得到了实现。

第二部分,是我们的主角,弄懂了这个函数,基本上就可以初步理解ECMAScript的对象模型了。而且,它的注释也很有意思,使用了cooperative bootstrapping magic这样的字眼。好的,那就让我们跑到后台去,看看魔术师的鬼把戏是怎么出来的吧。

js_InitFunctionAndObjectClasses仍然在同文件中,所以不用调转就可以找到。

/* If cx has no global object, use obj so prototypes can be found. */

if (!cx->globalObject)

JS_SetGlobalObject(cx, obj);

/* Record Function and Object in cx->resolvingTable, if we are resolving. */

。。。。

/* Initialize the function class first so constructors can be made. */

fun_proto = js_InitFunctionClass(cx, obj);

if (!fun_proto)

goto out;

/* Initialize the object class next so Object.prototype works. */

obj_proto = js_InitObjectClass(cx, obj);

if (!obj_proto) {

fun_proto = NULL;

goto out;

}

/* Function.prototype and the global object delegate to Object.prototype. */

OBJ_SET_PROTO(cx, fun_proto, obj_proto);

if (!OBJ_GET_PROTO(cx, obj))

OBJ_SET_PROTO(cx, obj, obj_proto);

这个程序的开头两大段,做的工作,我猜想我们可以跳过,不知道正不正确,我更想从js_InitFunctionClass(cx, obj)开始(标红的部分)。我们可以看到,我们还是把global当成参数传到了这个函数体中,这样,我们得到的的返回值,就是Function.prototype;同样,如果我们继续向下看,就会看到js_InitObjectClass(cx, obj)这个函数,从返回值、注释加上对函数名的推测,我们会看到,函数运行后返回了Object.prototype

然后呢,我们留意一下注释,哦,我的老天啊。我的猜测是没有错的Function.prototypeGlobal对象的prototype被委托给了Object.prototype.这还不够让我们兴奋的吗?

允许兴奋,可不要兴奋大发劲了啊。我们还有正事没有做呢。js_InitFunctionClass还在等着我们去解密呢。

这个函数在jsfun.c中有定义,麻烦你动手先将它找出来。

JSObject *

js_InitFunctionClass(JSContext *cx, JSObject *obj)

{

JSObject *proto;

JSAtom *atom;

JSFunction *fun;

proto = JS_InitClass(cx, obj, NULL, &js_FunctionClass, Function, 1,

function_props, function_methods, NULL, NULL);

if (!proto)

return NULL;

atom = js_Atomize(cx, js_FunctionClass.name, strlen(js_FunctionClass.name),

0);

if (!atom)

goto bad;

fun = js_NewFunction(cx, proto, NULL, 0, 0, obj, NULL);

if (!fun)

goto bad;

fun->u.i.script = js_NewScript(cx, 1, 0, 0);

if (!fun->u.i.script)

goto bad;

fun->u.i.script->code[0] = JSOP_STOP;

fun->flags |= JSFUN_INTERPRETED;

return proto;

为了简单起见,我将这个函数的调用图先列出来:

js_InitFunctionClass

JS_InitClass

js_Atomize

js_NewObject

js_NewGCThing

js_Atomize

js_NewFunction

js_NewGCThing

那么,我们可以从这个调用图中推导出什么来呢?咱们下回书接着说。

你可能感兴趣的:(JavaScript,REST,prototype,领域模型)