当前位置: 首页 > news >正文

[领域]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

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

相关文章:

  • java angularjs 跨域访问_AngularJS使用JSONP跨域问题(后台WebApi)
  • java throw throws_Java面试题 (2) Java中 throw 和 throws 的区别?
  • 2007年智能手机系统大战在即
  • java输入输出流课程_java day14第十四课 IO(输入、输出)流和JAVA目录操作
  • [领域]javascript hacking guide 第7部分
  • 浅谈Acegi配置
  • java valgrind_意外的内存泄漏[Valgrind]
  • 国内比较经典的图库资源网站
  • jstack 脚本 自动日志_Shell脚本实战:日志关键字监控+自动告警
  • 漫谈创业和管理-程序员5大思维障碍
  • mysql版本号字段比较大小_sqlserver中软件版本号进行字符串对比比较大小
  • 选择的自由
  • DSA and RBackupWindow
  • 慢连接 java_java nio 如何处理慢速的连接
  • 臭毛病从何而来
  • 【个人向】《HTTP图解》阅后小结
  • CNN 在图像分割中的简史:从 R-CNN 到 Mask R-CNN
  • Fabric架构演变之路
  • go append函数以及写入
  • HomeBrew常规使用教程
  • leetcode98. Validate Binary Search Tree
  • MobX
  • mongodb--安装和初步使用教程
  • Spark学习笔记之相关记录
  • SpiderData 2019年2月23日 DApp数据排行榜
  • 分享一个自己写的基于canvas的原生js图片爆炸插件
  • 今年的LC3大会没了?
  • 京东美团研发面经
  • 前端学习笔记之观察者模式
  • 详解移动APP与web APP的区别
  • 1.Ext JS 建立web开发工程
  • ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTr
  • #NOIP 2014# day.2 T2 寻找道路
  • (2)STM32单片机上位机
  • (4)通过调用hadoop的java api实现本地文件上传到hadoop文件系统上
  • (翻译)Quartz官方教程——第一课:Quartz入门
  • (附源码)spring boot基于Java的电影院售票与管理系统毕业设计 011449
  • (免费领源码)Python#MySQL图书馆管理系统071718-计算机毕业设计项目选题推荐
  • (十一)手动添加用户和文件的特殊权限
  • (四)Android布局类型(线性布局LinearLayout)
  • (转)清华学霸演讲稿:永远不要说你已经尽力了
  • .NET C# 使用 SetWindowsHookEx 监听鼠标或键盘消息以及此方法的坑
  • .NET Core 将实体类转换为 SQL(ORM 映射)
  • .NET Core 网络数据采集 -- 使用AngleSharp做html解析
  • .Net Winform开发笔记(一)
  • .NET/C# 异常处理:写一个空的 try 块代码,而把重要代码写到 finally 中(Constrained Execution Regions)
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .Net6使用WebSocket与前端进行通信
  • .net对接阿里云CSB服务
  • .net连接MySQL的方法
  • :O)修改linux硬件时间
  • @RunWith注解作用
  • [].slice.call()将类数组转化为真正的数组
  • [BROADCASTING]tensor的扩散机制
  • [c++] 什么是平凡类型,标准布局类型,POD类型,聚合体