类的使用和面向对象
大家都知道在cocos2d-x 底层是C++编写的,那么就有类的概念和继承机制。
但是在JS中,是没有类这个概念的,没有提供类,没有C++的类继承机制。
那么JS是通过什么方式实现简单的继承呢?JS是通过对象的原型实现继承。
我们来看一下这段代码:
var baselayer = cc.Layer.extend({ ctor:function(){ this._super(); cc.log("baselayer ctor read"); }, init:function(){ this._super(); cc.log("baselayer init read"); } });
我们申明了baseLayer对象 ,并且利用cc.Layer.extend,继承了CClayer。
那么问题来了?他究竟是怎么实现的呢?我们按住crtl跟进去看看cc.Layer.extend的实现;
ClassManager.compileSuper.ClassManager = ClassManager; /* Managed JavaScript Inheritance * Based on John Resig's Simple JavaScript Inheritance http://ejohn.org/blog/simple-javascript-inheritance/ * MIT Licensed. * 在这里申明了,实现JS继承的方式 是参考了 John Resig's 的一个例子来实现的;并且有原文地址,有兴趣的同学可以去看看原版实现方式 */ (function () { var fnTest = /_super/; var config = cc.game.config; var releaseMode = config[cc.game.CONFIG_KEY.classReleaseMode]; if(releaseMode) { console.log("release Mode"); } /** * The base Class implementation (does nothing) * @class */ cc.Class = function () { }; /** * Create a new Class that inherits from this Class * @static * @param {object} props * @return {function} */ cc.Class.extend = function (props) { //声明_super对象,并赋值为原型 var _super = this.prototype; // Instantiate a base Class (but only create the instance, // don't run the init constructor) //实例化创建prototype这个基类,只是创建实例,并没有跑init构造函数 var prototype = Object.create(_super); //给这个class复制ID标识,并且将_super对象添加到ClassManager类管理器中 var classId = ClassManager.getNewID(); ClassManager[classId] = _super; // Copy the properties over onto the new prototype. We make function // properties non-eumerable as this makes typeof === 'function' check // unneccessary in the for...in loop used 1) for generating Class() // 2) for cc.clone and perhaps more. It is also required to make // these function properties cacheable in Carakan. //进行函数的验证检测,以及设置他使用基本设置 var desc = { writable: true, enumerable: false, configurable: true }; //单例模式的基础申明 prototype.__instanceId = null; // The dummy Class constructor //创建Class这个类 function Class() { this.__instanceId = ClassManager.getNewInstanceId(); // All construction is actually done in the init method //如果这个类他存在.ctor方法,那么就默认的使用执行这个方法 //ctor在JS中就相当于构造函数 if (this.ctor) this.ctor.apply(this, arguments); } //给ID复制 Class.id = classId; // desc = { writable: true, enumerable: false, configurable: true, // value: XXX }; Again, we make this non-enumerable. desc.value = classId; Object.defineProperty(prototype, '__pid', desc); // Populate our constructed prototype object //把我们原型对象赋值 Class.prototype = prototype; // Enforce the constructor to be what we expect //将整个类赋值给desc.value desc.value = Class; //并且将类里构造的对象赋值 Object.defineProperty(Class.prototype, 'constructor', desc); // Copy getter/setter //模拟get/set的方式,使用cc.clone函数来拷贝 this.__getters__ && (Class.__getters__ = cc.clone(this.__getters__)); this.__setters__ && (Class.__setters__ = cc.clone(this.__setters__)); for(var idx = 0, li = arguments.length; idx < li; ++idx) { var prop = arguments[idx]; for (var name in prop) { var isFunc = (typeof prop[name] === "function"); var override = (typeof _super[name] === "function"); var hasSuperCall = fnTest.test(prop[name]); if (releaseMode && isFunc && override && hasSuperCall) { desc.value = ClassManager.compileSuper(prop[name], name, classId); Object.defineProperty(prototype, name, desc); } else if (isFunc && override && hasSuperCall) { desc.value = (function (name, fn) { return function () { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-Class //如果在新的对象方法里面添加._super(),他会继承父类的_super方法 //并且实现方法里面的所有对象及方法的赋值 this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]); Object.defineProperty(prototype, name, desc); } else if (isFunc) { desc.value = prop[name]; Object.defineProperty(prototype, name, desc); } else { prototype[name] = prop[name]; } if (isFunc) { // Override registered getter/setter //如果是方法,那么重载里面的属性,并且实现get,set方法可以直接使用 var getter, setter, propertyName; if (this.__getters__ && this.__getters__[name]) { propertyName = this.__getters__[name]; for (var i in this.__setters__) { if (this.__setters__[i] === propertyName) { setter = i; break; } } cc.defineGetterSetter(prototype, propertyName, prop[name], prop[setter] ? prop[setter] : prototype[setter], name, setter); } if (this.__setters__ && this.__setters__[name]) { propertyName = this.__setters__[name]; for (var i in this.__getters__) { if (this.__getters__[i] === propertyName) { getter = i; break; } } cc.defineGetterSetter(prototype, propertyName, prop[getter] ? prop[getter] : prototype[getter], prop[name], getter, name); } } } } // And make this Class extendable // 可以使用Class.extend来实现类的继承 Class.extend = cc.Class.extend; //add implementation method //添加要实现的方法 Class.implement = function (prop) { for (var name in prop) { prototype[name] = prop[name]; } }; return Class; }; })();
重点看3个点:
// The dummy Class constructor //创建Class这个类 function Class() { this.__instanceId = ClassManager.getNewInstanceId(); // All construction is actually done in the init method //如果这个类他存在.ctor方法,那么就默认的使用执行这个方法 //ctor在JS中就相当于构造函数 if (this.ctor) this.ctor.apply(this, arguments); }
第一,这个是在JS中的实现构造函数的方法,如果在自定义类中,存在有ctor:function()这个方法,那么他会
默认执行,默认成为构造函数;
desc.value = (function (name, fn) { return function () { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-Class //如果在新的对象方法里面添加._super(),他会继承父类的_super方法 //并且实现方法里面的所有对象及方法的赋值 this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]);
第二,desc.value在这个for循环中的赋值,实现了this._super()的原理,它会为派生类实完成对父类的实现;
通俗点来说,就是,如果我们想要继承并实现父类的方法,那么就需要在方法里面调用this._super()这个方法!
// And make this Class extendable // 可以使用Class.extend来实现类的继承 Class.extend = cc.Class.extend;
第三,讲cc.Class.extend赋值给Class.extend,就可以使用Class.extend来实现自定义类的继承;
OK,梳理完毕下面看看我们来学习一下怎么实现自定义类和自定义的继承:
var myLayer = baselayer.extend({ ctor:function(){ this._super(); cc.log("myLayer ctor read"); }, init:function(){ this._super(); cc.log("myLayer init read"); } });
这段代码中我从myLayer继承了父类baselayer,注意用法就是刚才我们Review底层代码时看到的
var myLayer = baselayer.extend({});
然后继续续实现ctor构造方法函数,和自定义方法函数init;
并且日志输出一下;
最终我们需要在MainScene中调用;
如下:
var MainScene = cc.Scene.extend({ onEnter:function(){ this._super(); var layer = new myLayer(); this.addChild(layer); } });
我们首先只调用
var layer = new myLayer();
看看最终输出是什么?
从输出可以看出他先调用了baselayer,再调用了myLayer;
那么就可以理解为我们直接new myLayer() 会直接自动实现调用我们写的ctor构造函数方法;
而且是先调用父类,然后再调用我们的派生类自定义类;
他并没有主动调用init:function()这个方法,因为他是我们自定义的,所以需要我们手动去调用
layer.init();
OK,我们加上手动调用后再来看一下输出是什么?
我们可以看到了前两行输出都是 ctor 先执行;
init 函数后执行;
而且调用也是 先执行baseLayer 我们的父类的init函数 再执行我们的自定义init方法!
现在就非常清晰了,我们的myLayer.init方法继承了baseLayer.init的属性方法;
而且实现的原理就是通过this._super()来实现的!
我们再修改一下代码来看看是不是这样,将myLayer类里面的init方法里面的this._super();这句话去掉!
看看我们的baseLayer.init方法会不会被调用
var myLayer = baselayer.extend({ ctor:function(){ this._super(); cc.log("myLayer ctor read"); }, init:function(){ cc.log("myLayer init read"); } });
看看输出: