去验证码文件对javascript模块化编程的完美诠释
通过学习Taobao的UA算法文件6x.js和去验证码文件nc.js来理解javascript的模块化编程,胜过读N本关于javascript模块化编程的书籍。去验证码文件nc.js与Ua算法文件6x.js的模块化编程方式类似,但不完全相同,本文以nc.js文件中的STABLE_ACTION为例来记录其对javascript的模块化编程的完美诠释。
本系列文章将以taobao的去验证码文件nc.js为主要学习对象,同时会涉及淘宝的login.html, 6x.js等相关文件,这些文件与64.js是同一时期抓取的,与目前最新的相关文件可能会略有差异,请各位看官知悉,nc.js的下载链接。去验证码文件nc.js功能框架与模块化结构的简陋分析请参阅tb去验证码文件nc.js功能框架与模块化结构浅析。
STABLE_ACTION的结构概述
下图是函数STABLE_ACTION的结构示意图,STABLE_ACTION包含主体函数function e(t,n,o)和该主体函数的三个参数。第一个参数为obejct,有24个函数模块,这24个模块均是由两个对象组成的数组,第一个元素是当前模块的主要功能函数,第二个元素是当前模块需引用的外部模块,当前模块不需要引用外部模块时,其值为空;第二个参数为空的object;第三个参数为Array,该Array中有一个元素,值为2。
当函数STABLE_ACTION被执行时,首先会执行主体函数中的for循环,其中o.length=1, o[0]=2,所以会调用 i(2),接下来我们来关注主体函数中的子函数funtcion i(c,r)。
STABLE_ACTION的主函数体浅析
浅析STABLE_ACTION的主函数体时,需要两张图来辅助说明,这里将”!function e(t,n,o)”所在图称为图1,该图包含STABLE_ACTION的主函数体;将“2 : [function (e, t, n) {”称为图2,该图包含主函数体参数中的元素2。
在图1中,我们可以看到主体函数中的子函数funtcion i(c,r)最重要的代码就是t[c][0].call这一句。当STABLE_ACTION的for循环调用i(2)时,t[c][0].call的效果为l.exports.t[2][0](function(e){/*省略函数体*/}, l, l.exports, e, t, n, o);这里的l.exports.t[2][0]即指向24个模块中的模块2,即图2中的函数function (e, t, n) {}。
而图2中的函数function (e, t, n) {}的三个参数则分别对应图1中”t[c][0].call(l.exports, function (e) {“语句中的匿名函数function (e){}, l , l.exports。
图2是模块2的缩略图,模块2需要调用外部模块,因此其第2个元素是有值的,它调用外部模块的方式是通过“t[c][0].call(l.exports, function (e) {“语句中的function (e){}。例如语句e(“./_styl/nc”)的效果等同于执行匿名函数function(e){},如图1中的注释所示。其他模块的调用也是用相同的方式,满满的都是技巧。
图1的主体函数!function e(t,n,o)中的n初始是空的obejct,在每个模块第一次被调用(初始化)时,该模块会被存储在对象n中。每次调用函数i(c)时,都会先判断当前模块是否已被初始化,若已初始化,则可以直接通过n[c].exports调用。1~24的参数模块中,若对第一个元素function (e, t, n)中的n直接赋值,即相当于对n[c].exports赋值,例如模块3中有如下代码,因此模块3初始化完成之后,在n[3].exports就会有相应的函数出现,如下图所示。
1 2 |
n.getSecToken = r, n.getNCToken = l |