因为工作需求我也开始接触这个框架,前面开始可能会有一些废话。我是希望分享我分析学习的一个过程。
假设是一个不太懂JS开发者,看到这些代码?应该会头晕脑胀吧,但是别怕,我逐步逐步来分析它。
我想说的是,在面对一大堆,我们看不懂的代码的时候,该怎么入手?
从基础入手,看这段代码,哪些是我们懂的?
cc是什么?大家想想什么类型可以用点来访问?是不是只有对象才拥有属性?那我们知道cc是一个对象,虽然我们不知道它有什么用。
cc.game是什么?cc是对象,通过点来访问它的game属性,game是cc的属性,那它又是个什么东西呢?是不是又通过点来访问一个属性?虽然我们不知道cc的game属性有什么用处?但是我们知道它是一个对象。
cc.game.onStart=funct是什么?onStart是game通过点来访问的,它是game的属性,然后给赋值为一个函数,我们虽然不知道game的onStart方法有什么用处?但是我们知道它是一个方法。
不知道大家有没有感觉,它其实也没有那么ko怕,就一个对象内的属性或方法而已。
接下去该分析哪里呢?onStart方法?不是的,想想,其实写JS是不是,总归就是执行与赋值,还会有其他?可能我考虑的很浅,但我们暂且把一个js的文件分为赋值和执行,那么在想想赋值和执行。在这个main.js,就一个赋值,和一个执行,哪个才是入口点呢?(当我们分清楚了这个页面的无非是给对象赋值,和执行对象的方法。)
想想cc.game.onStart赋值是为了什么,为了接下来可以执行它,main.js并没有执行cc.game.onStart方法。但会发现在给onStart赋值以后,执行了cc.game对象的run方法。
不难想到,cc.game.run方法必定执行了cc.game.onStart()方法。
所以我们先来定位cc.game.run方法,定位方法有很多,我这边是直接用谷歌浏览器console.log(cc.game.run);,在右边会看到。
来看一下cc.game.run方法,它做了3件事:
1.定义了个self变量,赋值this,这里的this指向哪里?cc对象?不是的!This指向的是cc.game对象,run方法是隶属于cc.game对象而不是cc对象,简单的断点一下,this===cc.game观看返回值即可。
2.定义了个_run函数,至于执行了什么,待我们执行该函数,在来分析。
3.document.body?Func1():Func2(),这里的是一个三元表达式,有没有这个document.body对象,决定了接下去执行的方向,(这里呢?因为源码太多了,不可能就是全部都分析,只能跟着正常情况走),那么正常情况下document.body是body元素,那什么情况不会,document.body为空false呢?试着在head标签的尾部添加一个script标签,然后断点一下,审查元素,打印一下。
这时发现,在这种情况下,document.body为false执行cc._addEventListener()方法,其实看到这个方法名,大家应该都很熟悉,直接来定位或者打印一下。
就是给window对象绑定load事件,当Dom加载完毕,解绑this所指向的对象(window)的load事件,解绑的时候必第二个参数必须是绑定的方法,arguments.callee其实就是
解绑完毕后,执行_run方法,这样做是为了防止Dom没加载完毕,就执行_run方法。
来到_run方法,这里面有3个if语句
1.第一个if语句是判断id,但我们在执行cc.game.run方法的时候并没有值,所以这里铁定不是走的,但是,我们可以试着打印里面的值来挖掘一下这东西,到底有什么用,
看到这2个字符串有何感想,gameCanvas是不是和index.html的canvas元素id值,self在_run方法的作用域下面并没有声明,那往上走在cc.game.run方法的作用域下找到self。
现在知道self其实就是cc.game对象,
如果我们要改变要改变canvas的id的话,那么执行cc.game.run方法,时候,传参我们改变id的name就可以了。
2.第二个if语句是取反cc.game._PRepareCalled属性为false的时即执行cc.game.prepare方法,默认的cc.game._prepareCalled属性为false,所以这个if语句是必定执行的。
那来走一下cc.game.prepare方法:
(在分析这个方法之前我看了一下,发现这个方法,不想之前遇到那些方法一样简短,在这个方法定义的几个变量,都是保存了对象或者是属性,所以从表面来看,除非你对cocos2d-js这个框架很熟悉,不然的话单纯从变量名用意来得知它的用意)
所以这里的变量我先通过打印它的值来罗列一下,待要用到的时候,才来分析它们。这张图算是prepare这个方法的上半段吧。
2.1.这里是先罗列打印了5个变量
2.2接下来是一个if语句,cc._supportRender属性,这里我打印了一下是true,取反的话这个if语句是不会被执行的,执行内容是自定义了错误。反过来想想这东西既然可能是true那么也可能是false,那不然它写这个有什么意义,我这不是废话呢,那么这个cc._supportRender属性应该是判断是否支持某些功能给它赋值。看一下翻译了错误信息,得知是:渲染器不支持rendermode。所以这里来Ctrl+F一下设置cc._supportRender属性位置。往上查找,会找到一个匿名自执行函数,尝试断点一下,会发现,该匿名函数执行在ccBoot.js内,在main.js之前引入,初始化的时候,这个匿名自执行函数会在我们执行cc.game.run之前执行。
来分析一下,还是老思路,变量太多了,罗列打印一下。
看到这列值,其实没什么好说的,抓几个来说,sys形参的OS_ANDROID属性是字符串,加了括号,赋值给shideldOs就成数组了。cc.newElement方法,returndocument.createElement,这里是创建了个canvas元素。我们的主角cc._supportRender这里被设置成为false。
还有就是win.WebGLRenderingContext,会发现自执行函数并没有win变量,我打印了一下是window对象,估计是上级作用域定义了,有这个win.WebGLRenderingContext方法的浏览器便支持canvas3D。
接下来是2个if语句:
其实不看判断语句,单从执行的语句来看,不难发现第一条if语句是执行3D的,第二条是支持2D的,在第一条if语句会看到逻辑与supportWebGL,supportWebGL保存了window.WebGLRenderingContext,如果浏览器不支持,第一个if语句是不会通过的。我这里用的是谷歌浏览器所以走的是第一条if语句。
这里再次做了个if语句,必须cc.create3DContext方法执行完毕后,返回值不为false,才把主角cc._supportRender设置为true。来打印一下cc.create3DContext方法:
定义一串数组,这是启动canvas3D的各个浏览器名字,应该是canvas3D各个浏览器还未统一吧,for循环,创建成功即break跳出循环,返回context,如果4个都不行的话,返回就是null。
cc._supportRender的初始化设置就到一段落了。
好,继续回到cc.game.prepare方法(上半段的最后2个赋值语句)
设置了cc.game._prepareCalled属性的值为true,jsList是一个数组,有什么用呢? 留一个疑问
3.cc.game.prepare方法(下半段):下半段是一个ifelse语句:
我打印了一下cc.Class,结果是undefined,我试着检索了一下,CCBoot.js,并没有设置cc.Class属性的,所以这里试着来看一下loader.loadJsWithImg方法。loader保存的是cc.loader。定位一下。
断点,强制设置cc.Class为true。(注意,这里的cc.Class,应该是哪里出现问题cc.Class才会为true,从而走这条路线呢?我们这里没有遇到这个问题,但是还是分析一下,最后分析完这条路线,应该总结一下,什么情况才会走这条路,所以这一段会比较枯燥,也可能不准确,因为我们是强制执行它的,参数什么的也可能不对,导致我们曲解它最终要实现的效果)
3.1Self保存的是cc.loader
3.2jsLoadingImg是保存了执行cc.loader._loadJsImg方法的返回值。定位一下这个方法:
d.getElementById(cocos2D_loadJsImg)这个是什么,打开index.html的时候,会发现一开始有一个load动画,断点一下会发现:
If语句是取反,没有这个元素的即,重新创建一个img元素,设置src,添加到画布内等等等。。。,最后都是返回这个元素。
3.3agrs是保存了执行cc.loader._getArgs4Js方法的返回值。定位一下这个方法:
这里最终返回results,初始化results数组,反正这里就是根据args的长度,来保存设置results的值得。
这里是返回的结果。
3.4执行cc.loader.loadJs方法。定位一下这个方法:
3.4.1self保存的是cc.loader
3.4.2args同3.3
3.4.3preDir,list,callback
这个一直是我们执行cc.loader.loadJsWithImg的传参
3.4.4(navigator.userAgent.indexOf("Trident/5")>-1)判断浏览器是否包含Trident/5,网上检索一下这是来判断Win7的ie9,即执行cc.loader._loadJs4Dependency,
3.4.4.1jsList:["src/resource.js","src/app.js"]长度小于等于0执行cb
新闻热点
疑难解答