最近聽說Cocos2d JS官方在組織寫新的代碼例子。并且林順同學(xué)在開會時說,Cocos2d JS接口將回歸JS風格,成員變量訪問方式用“.”,以及初始化時用對象字面量{}。非常不錯啊。
如果之前是Cocos2d-x的C++程序員,在使用Cocos2d JS時很容易沿用C++的思路來寫腳本。這種方式不容易發(fā)揮出腳本語言的快速開發(fā)優(yōu)勢。
在Cocos2d-x 的例子代碼中有一些寫法,尤其是在Test中,有許多代碼是按照C++例子原樣翻譯過來的。里面應(yīng)用了很多繼承與組合等代碼組織方式。并且,很多靜態(tài)強類型語言的寫法(類型強迫癥),在腳本語言中對于開發(fā)速度是有很大影響的。
一、繼承VS動態(tài)添加成員
繼承,是一種最重量級的代碼復(fù)用方式(他有自己的優(yōu)勢但是也有非常多的副作用)。但是問題在于,很多編輯器和運行庫是既不支持協(xié)變又不支持各種動態(tài)綁定。這種情況下會讓你的繼承代碼毫無作用。你只能選擇組合,而組合差不多是一種最羅嗦的代碼復(fù)用方式。他會很大程度抵消你的腳本語言開發(fā)速度優(yōu)勢。從這種情況看來CocosBuilder的設(shè)計無疑比CocoStudio要先進許多。
那么怎么做呢?因為腳本語言的優(yōu)勢可以在運行時動態(tài)給一個實例添加成員。 (Dynamic addition of methods and attributes to instances.)使用這種特性就可以跳過繁瑣的繼承+組合復(fù)用方式來構(gòu)建代碼。并且Cocos2d-x作為游戲引擎,因為存在UI等顯示系統(tǒng),也就是說存在一個全局節(jié)點樹,可以用來遞歸遍歷所有顯示對象,使用類型判定然后直接調(diào)用相應(yīng)的擴展函數(shù)直接在對象實例上進行擴展。
上面說的是指基于Cocos2d JS的二次開發(fā)代碼的使用方法。在編寫功能代碼時也可以應(yīng)用這種特性。
這么做的壞處是會破壞JS內(nèi)部的類型系統(tǒng)(構(gòu)造器與對象行為不匹配)。如果庫的編寫者和使用者沒有充分溝通,可能會遇到無法理解的代碼。讓對象行為變得不可控,因為JS本身就是動態(tài)弱類型的。所以一定要嚴格限制功能代碼中被擴展的對象的作用范圍和使用范圍,必要時使用文檔規(guī)范,避免其他人接手莫名其妙的代碼。
而對于自帶運行庫的編輯器來說,還有第二種選擇——直接擴展插件。這是完全按照強類型的路子走了。
二、裝載時執(zhí)行OR裝載時注冊啟動時初始化
代碼在加載時可以執(zhí)行,這是腳本語言的又一個特色。因此我們可以在代碼文件被裝載時自動做很多初始化工作。
但是這么搞也是存在一定問題的,如果初始化代碼散落在不同的文件中,對debug是不利的。需要在多個調(diào)用點去來回查找。
不過凡事都有例外,如果你把很多代碼當成資源加載,就不存在這種問題。比如,加載一些AI腳本、動畫腳本、UI腳本的時候,就不存在這種問題。因為這些代碼的接口規(guī)范都很統(tǒng)一,而且一定會有一個外部裝載機制和管理機制。先通過讀取文件將啟動函數(shù)綁定好,再統(tǒng)一啟動。
三、具名索引And有限狀態(tài)機FSM
訪問一個對象的成員,可以用[]內(nèi)嵌名字(具名索引access attribute by name),也可以用.后面加名字。我建議動態(tài)獲得的成員名進行訪問時使用前一種方式,普通的成員訪問時候使用后一種,以示區(qū)別。
尤其是通過[]內(nèi)嵌名字方式,可以直接調(diào)用函數(shù)這種方式,可以非常好的同游戲中的各種狀態(tài)機制和腳本指令結(jié)合。比狀態(tài)模式(基于對象和接口)與狀態(tài)變量(基于switch-case)要簡便許多。
四、文件訪問域And模塊化
JavaScript的函數(shù)級作用域其實是很討厭的。有幾條原因:
1.一不小心很容易就污染了全局變量和全局函數(shù)
2.因為1的原因如果你選擇對象構(gòu)造方式來避免污染全局作用域又會遇到另外一個問題就是this。這個this不但羅嗦,每句都得寫。還常常亂變,例如:bind callback的時候,在回調(diào)函數(shù)啟動的時候,你常常無法確定當前this到底是哪個對象。(當然,在JS中也有一種叫bind this的技術(shù),但有句話是:與其每次都解決問題,不如根本沒問題)
Coffee是用閉包方式構(gòu)造一個“文件訪問域”的,還有很多庫也有這種功能。這可以讓你:
1.省掉寫this
2.不會污染全局
當然如果你能支持module require還可以做更多的功能模塊化開發(fā)(這對于前后端統(tǒng)一JS開發(fā)也很有好處)。官方介于閉包的性能和兼容性問題(都要考慮瀏覽器),應(yīng)該不會添加CommonJS支持。
五、匿名回調(diào)函數(shù)
在bind callback時,直接通過匿名函數(shù)方式打入回調(diào)函數(shù),是一種不錯的方式,能夠少寫很多代碼。
但是很多時候,如果遇到復(fù)雜流程控制,多種狀態(tài)切換時,這種原地展開的callback,就會讓代碼可讀性和錯誤查找變得困難起來,并且由于這種寫法的上下文非常隱晦,還會引入this問題。
對于簡單的UI顯示控制,純顯示效果調(diào)用,匿名函數(shù)這種方式還是可以的。但是如果遇到復(fù)雜流程,并且牽扯到上下文,邏輯控制,函數(shù)復(fù)用,還是老老實實寫實現(xiàn),然后再bind callback時bind 函數(shù)比較好一點。
最后
都說JS的代碼編寫很多時候是基于函數(shù)的。卡哥的名言——“很多時候需要的僅僅是一個函數(shù)”。
寫功能代碼的時候。相對于OO,很多時候,你需要的是一個有用的對象,而不是類。對于類使用,在傾向于封裝代碼和類型約定(這個便于review和debug),但是如果說為了復(fù)用,明顯有點太扯了(離需求太近,專門定制化的類,復(fù)用一定成問題)。當然關(guān)心代碼質(zhì)量和復(fù)用是好事,但是搞成項目改得精疲力盡就得不償失了。
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機、免備案服務(wù)器”等云主機租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。