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