由於工做需求我也開始接觸這個框架,前面開始可能會有一些廢話。我是但願分享我分析學習的一個過程。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的事情,由於工做緣由,我又得投入其餘學習,因此有空儘可能更新,把它寫好點。