大话cocos2d-js(1)

  由于工做需求我也开始接触这个框架,前面开始可能会有一些废话。我是但愿分享我分析学习的一个过程。html

 

 

 

  假设是一个不太懂JS开发者,看到这些代码?应该会头晕脑胀吧,可是别怕,我逐步逐步来分析它。json

 

  我想说的是,在面对一大堆,咱们看不懂的代码的时候,该怎么入手?canvas

 

  从基础入手,看这段代码,哪些是咱们懂的?api

 

  cc 是什么?你们想一想什么类型能够用点来访问?是否是只有对象才拥有属性?那咱们知道cc是一个对象,虽然咱们不知道它有什么用。数组

 

  cc.game 是什么? cc是对象,经过点来访问它的game属性,game是cc的属性,那它又是个什么东西呢?是否是又经过点来访问一个属性?虽然咱们不知道cc的game属性有什么用处?可是咱们知道它是一个对象。浏览器

 

  cc.game.onStart = funct 是什么?onStart是game经过点来访问的,它是game的属性,而后给赋值为一个函数,咱们虽然不知道game的onStart方法有什么用处?可是咱们知道它是一个方法。app

 

  不知道你们有没有感受,它其实也没有那么ko怕,就一个对象内的属性或方法而已。框架

 

  接下去该分析哪里呢?onStart方法?不是的,想一想,其实写JS是否是,总归就是 执行 与 赋值,还会有其余?可能我考虑的很浅,但咱们暂且把一个js的文件分为 赋值 和 执行,那么在想一想赋值和执行。在这个main.js,就一个赋值,和一个执行,哪一个才是入口点呢?(当咱们分清楚了这个页面的无非是给对象赋值,和执行对象的方法。)异步

 

  想一想cc.game.onStart赋值是为了什么,为了接下来能够执行它,main.js并无执行cc.game.onStart方法。但会发如今给onStart赋值之后,执行了cc.game对象的run方法。async

 

  不难想到,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方法,return document.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方法(下半段):下半段是一个 if else语句:

 

  我打印了一下cc.Class,结果是undefined,我试着检索了一下,CCBoot.js,并无设置cc.Class属性的,因此这里试着来看一下loader.loadJsWithImg方法。loader保存的是cc.loader。定位一下。

 

  断点,强制设置cc.Class为true。(注意,这里的cc.Class,应该是哪里出现问题cc.Class才会为true,从而走这条路线呢?咱们这里没有遇到这个问题,可是仍是分析一下,最后分析完这条路线,应该总结一下,什么状况才会走这条路,因此这一段会比较枯燥,也可能不许确,由于咱们是强制执行它的,参数什么的也可能不对,致使咱们曲解它最终要实现的效果)

 

  3.1 Self保存的是 cc.loader

  3.2 jsLoadingImg是保存了执行cc.loader._loadJsImg方法的 返回值。定位一下这个方法:

 

  d.getElementById(cocos2D_loadJsImg)这个是什么,打开index.html的时候,会发现一开始有一个load动画,断点一下会发现:

   

  If语句是取反,没有这个元素的即,从新建立一个img元素,设置src,添加到画布内等等等。。。,最后都是返回这个元素。

 

  3.3 agrs是保存了执行cc.loader._getArgs4Js方法的 返回值。定位一下这个方法:

 

  这里最终返回results,初始化results数组,反正这里就是根据args的长度,来保存设置results的值得。

  这里是返回的结果。

 

  3.4 执行cc.loader.loadJs方法。定位一下这个方法:

 

  3.4.1 self保存的是cc.loader

  3.4.2 args 同 3.3

  3.4.3 preDir,list,callback

这个一直是咱们执行cc.loader.loadJsWithImg的传参

 

 

  3.4.4 (navigator.userAgent.indexOf("Trident/5") > -1)判断浏览器是否包含Trident/5,网上检索一下这是来判断win7的ie9,即执行cc.loader._loadJs4Dependency,

 

 

  3.4.4.1 jsList:["src/resource.js", "src/app.js"] 长度 小于等于0 执行 cb(异常方法)

  3.4.4.2 self保存的是cc.loader

  3.4.4.3 执行 cc.loader._createScript 来定位一下这个方法:

 

  看到这里整个头晕,(这里不是用ie9)抓重点讲,建立 script元素,而后来判断,判断传参jsPath["src/resource.js", "src/app.js"],设置异步,给script 绑定load/error事件,加载完毕删除元素,解除绑定事件。添加到body元素。Js就会进行加载了,走到这里能够判断,cc.Class为true的状况,多是处理没加载到 没加载 到project.json文件内jsList设置好的连接。

 

  3.4.5 由于我用的是谷歌浏览器,不是ie9,继续往下走,执行cc.async.map方法,来定位一下这个方法:

 

  3.4.5.1 locTterator 保存了 形参iterator(一个函数)

  3.4.5.2 形参iterator是一个function 因此这个if语句不会走。。。

  3.4.5.3 构造了一个asyncPool对象,而且执行asyncPool对象下的方法flow,最后是返回asyncPool,因此这里来看建立这个对象后执行flow方法,有什么用。。。定位一下:

     这里要说的是不直接分析这个构造函数,并且直接来看flow的方法实现了什么功能,由于一个构造函数,构造一个对象,一个对象可能会有不少属性,不少方法,在不知道这个对象到底的干什么的用的时候来分析它,感受会有点枯燥。在这以前我是打算直接,分析这个构造函数的,可是发现特别。。,而且中文api文档并无这个的解释,英文的有解释,也就2句。。因此这里就直接看它的方法是实现什么功能。

 

 

  3.4.5.3.1 Self 指向 构造出来的对象,指向 cc.AsyncPool.prototype

  3.4.5.3.2 if语句,条件this._pool属性的长度不等于0,因此这里是不会执行。

  3.4.5.3.3 for循环 执行 cc.AsyncPool.limit次数的 cc.AsyncPool._handleeItem方法,到这这里,在来看cc.AsyncPool构造函数的属性就不那么枯燥了,次数是怎么得来的呢?

 

  若是一开始就来分析这些属性,估计也说不出个之因此然来,来看一下 构造对象的时候传入的参数

 

  Cc.each,的方法实现相信你们不陌生的,这里就不说了,遍历数组srcObj以对象的形式{index:num,value:string}push进this._pool数组,因此这里的this.size的保存了this._pool数组的长度,最后,this._limit 用逻辑或来赋值,固然不会是自己,自己是0;

 

  好,如今知道执行次数,this._handleItem来看一下这个方法实现的了什么功能?

 

  3.4.5.3.4 Self 指向 构造出来的对象,指向 cc.AsyncPool.prototype

  3.4.5.3.5 item保存了self._pool数组删除掉的第一个元素值。要执行2次,下次在执行的话,保存的就是当前的第二个元素,self._pool数组也为空。

  3.4.5.3.6 value保存了item对象的value属性,index保存了item对象的index属性。

  3.4.5.3.7 改变用self-_iterator 方法的对象为 self._iteratorTarget(这里是undefined),

 

 

 

 

  这里的self._iteratorTarget是undefined,而后我再试着在 self._iterator方法内断点,打印this,或者是模拟一个函数,把对象假装成undefined,结果this都指向window对象。因此也就这样。

 

  3.4.5.3.8 执行cc.path.join方法,接受2个值,返回赋值给 jsPath,来定位一下方法。

 

  遍历传参,返回去除指定字符后拼接成连接。

 

  3.4.5.3.9 if语句内localJsCache对象为空,也就是说这个语句不会触发。

  3.4.5.3.10 self._createScript这个方法,是否是很熟悉,在前面 ie9的状况

 

  因此最后大胆的猜想。来总结cc.Class,多是project设置了的文件没加载到,因此它们会重复请求,仍是没有的话就会抛出异常。可是通过测试,若是就加载project预设的文件走的不是cc.Class这个if语句。因此大致经过给cc.Class赋值为true,也算是分析了它干了写什么。

 

  这一章就到这里,但愿下面会解决这个疑问。最后就是关于暴力分析backbone.js的事情,由于工做缘由,我又得投入其余学习,因此有空尽可能更新,把它写好点。

相关文章
相关标签/搜索