對於面向對象語言來說,繼承機制是代碼復用的基礎,很不幸的是javascript作為一個基於原型繼承的語言,並沒有在本身語言層面上直接作出對類繼承的支持。
但是js語言擁有很強大的表現力。所以一般是js的使用者自行設計一套繼承機制,這個機制必須包括幾個點,對私有訪問權限的模擬,對屬性和類屬性的不同實現,對方法覆蓋的支持,對父類被覆蓋方法的訪問等。
cocos2d-x中,整合了兩套繼承機制,看《MoonWarriors》例子中的源碼SysMenu.js文件
- var SysMenu = cc.Layer.extend({
- _ship:null,
- ctor:function () {
- cc.associateWithNative( this, cc.Layer );
- },
- init:function () {
- var bRet = false;
- if (this._super()) {
- winSize = cc.Director.getInstance().getWinSize();
- var sp = cc.Sprite.create(s_loading);
- sp.setAnchorPoint(cc.p(0,0));
- this.addChild(sp, 0, 1);
- var logo = cc.Sprite.create(s_logo);
- logo.setAnchorPoint(cc.p(0, 0));
- logo.setPosition(0, 250);
- this.addChild(logo, 10, 1);
- var newGameNormal = cc.Sprite.create(s_menu, cc.rect(0, 0, 126, 33));
- var newGameSelected = cc.Sprite.create(s_menu, cc.rect(0, 33, 126, 33));
- var newGameDisabled = cc.Sprite.create(s_menu, cc.rect(0, 33 * 2, 126, 33));
- var gameSettingsNormal = cc.Sprite.create(s_menu, cc.rect(126, 0, 126, 33));
- var gameSettingsSelected = cc.Sprite.create(s_menu, cc.rect(126, 33, 126, 33));
- var gameSettingsDisabled = cc.Sprite.create(s_menu, cc.rect(126, 33 * 2, 126, 33));
- var aboutNormal = cc.Sprite.create(s_menu, cc.rect(252, 0, 126, 33));
- var aboutSelected = cc.Sprite.create(s_menu, cc.rect(252, 33, 126, 33));
- var aboutDisabled = cc.Sprite.create(s_menu, cc.rect(252, 33 * 2, 126, 33));
- var newGame = cc.MenuItemSprite.create(newGameNormal, newGameSelected, newGameDisabled, function () {
- this.onButtonEffect();
- flareEffect(this, this, this.onNewGame);
- }.bind(this));
- var gameSettings = cc.MenuItemSprite.create(gameSettingsNormal, gameSettingsSelected, gameSettingsDisabled, this.onSettings, this);
- var about = cc.MenuItemSprite.create(aboutNormal, aboutSelected, aboutDisabled, this.onAbout, this);
- var menu = cc.Menu.create(newGame, gameSettings, about);
- menu.alignItemsVerticallyWithPadding(10);
- this.addChild(menu, 1, 2);
- menu.setPosition(winSize.width / 2, winSize.height / 2 - 80);
- this.schedule(this.update, 0.1);
- var tmp = cc.TextureCache.getInstance().addImage(s_ship01);
- this._ship = cc.Sprite.createWithTexture(tmp,cc.rect(0, 45, 60, 38));
- this.addChild(this._ship, 0, 4);
- var pos = cc.p(Math.random() * winSize.width, 0);
- this._ship.setPosition( pos );
- this._ship.runAction(cc.MoveBy.create(2, cc.p(Math.random() * winSize.width, pos.y + winSize.height + 100)));
- if (MW.SOUND) {
- cc.AudioEngine.getInstance().setMusicVolume(0.7);
- cc.AudioEngine.getInstance().playMusic(s_mainMainMusic, true);
- }
- bRet = true;
- }
- return bRet;
- },
- onNewGame:function (pSender) {
- var scene = cc.Scene.create();
- scene.addChild(GameLayer.create());
- scene.addChild(GameControlMenu.create());
- cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene));
- },
- onSettings:function (pSender) {
- this.onButtonEffect();
- var scene = cc.Scene.create();
- scene.addChild(SettingsLayer.create());
- cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene));
- },
- onAbout:function (pSender) {
- this.onButtonEffect();
- var scene = cc.Scene.create();
- scene.addChild(AboutLayer.create());
- cc.Director.getInstance().replaceScene(cc.TransitionFade.create(1.2, scene));
- },
- update:function () {
- if (this._ship.getPosition().y > 480) {
- var pos = cc.p(Math.random() * winSize.width, 10);
- this._ship.setPosition( pos );
- this._ship.runAction( cc.MoveBy.create(
- parseInt(5 * Math.random(), 10),
- cc.p(Math.random() * winSize.width, pos.y + 480)));
- }
- },
- onButtonEffect:function(){
- if (MW.SOUND) {
- var s = cc.AudioEngine.getInstance().playEffect(s_buttonEffect);
- }
- }
- });
- SysMenu.create = function () {
- var sg = new SysMenu();
- if (sg && sg.init()) {
- return sg;
- }
- return null;
- };
- SysMenu.scene = function () {
- var scene = cc.Scene.create();
- var layer = SysMenu.create();
- scene.addChild(layer);
- return scene;
- };
這個extend繼承寫法由John Resig創造,John Resig是JS領域的大神,而且網上有很多粉絲給他編的段子,非常有趣。
例子中使用父類cc.Layer.extend方法來啟動繼承,傳入一個對象字面量{},這個字面量可以包含對象屬性和對象方法,最終由extend來完成接口綁定,返回一個構造函數賦值給SysMenu。
對於類方法也就是通常意義上的靜態方法),使用的是js最傳統的方式,直接給構造函數指定屬性即可。
這種編寫代碼的方式非常簡單,而且也很優美。更重要的是,這種寫法,非常符合C++或java程序員的排版審美。
關於繼承的理解。js裡面的原型繼承和基於類的繼承方式截然不同,內部是在維護一個原型鏈,鏈上的節點與節點之間是鏈接關系注意:不是賦值,也不是拷貝)。可以先看一下《權威指南》那本書是怎麼講的,不過很遺憾,那本書關於原型繼承的圖解畫的不太好……千萬不要搞代數式的替換和死記硬背,那樣你很難掌握原型鏈的本質。
另外,強烈推薦三生石上的系列文章《JavaScript繼承詳解》
JavaScript繼承詳解
JavaScript繼承詳解二)
JavaScript繼承詳解三)
JavaScript繼承詳解四)
JavaScript繼承詳解五)
JavaScript繼承詳解六)
有時間的話,我會把三生石上的文章配一些詳細的原型鏈描述圖,這樣就可以很容易的掌握js的原型鏈了。
本文出自 “老G的小屋” 博客,請務必保留此出處http://4137613.blog.51cto.com/4127613/1125167