网上的众多javascript继承方式,这里是不会详细讲解的,需要的,请自己度娘或谷爹。
之前做cocos2d-js的游戏,发现它有一个很有趣的继承方式。
形式如下:
var A = cc.Class.extend({ // 一系列的函数等 ctor: function(){ // this._super指向了父亲的ctor方法,不明觉厉啊 this._super(); } });
于是研究了一下,主要有几点需要注意的:
1、function.toString会返回整个函数的定义字符串
2、str.indexOf方法,有两个参数,第一个是字符串,第二个是起始检查的位置,它第一次匹配上,就结束了
3、它的this._super方法,是通过匹配 或
闭包改写,弄出来的
于是,尝试了一下,自己去实现:
function Class(){}; // compileSuper在某些特定情况下,才有用咯~,不过,它更节省内存空间,如果不需要调试,可以启用这种继承 Class.compileSuper = function(fnStr, fnName){ // 找出fn的参数 var pstart = fnStr.indexOf("("), pend = fnStr.indexOf(")"); var params = fnStr.slice(pstart + 1, pend); // 从fn主体开始寻找 var str = fnStr.substring(fnStr.indexOf("{") + 1, fnStr.lastIndexOf("}")); // 替换掉this._super,为this.super[name] // cocos2d-js里,是通过for循环来实现的,但因为这里多记录了一个super字段,所以没有它的烦恼~ var keyName = "this.super." + fnName; str = str.replace(/this._super/g, "this.super && " + keyName + " && " + keyName); // 返回新的函数 return new Function(params, str); }; Class.extend = function(proto){ var _super = this.prototype; function myClass(){ this.ctor && this.ctor.apply(this, arguments); }; var fn = myClass.prototype; // 下面这个for循环,如果再包装一下,就可以实现多参数形式了~,实验,不过多考虑 for(var key in proto){ // 当前的item var item = proto[key]; // 如果父类和当前,都是函数,则有继承关系 var isSuperFunc = "function" == typeof _super[key], isFunc = "function" == typeof item; if(isFunc && isSuperFunc){ // 实现继承,包装一个super方法,如果存在_super这样的字段,则编译 var reg = /\b_super\b/, itemStr = item.toString(); if(reg.test(itemStr)){ // 有_super方法,则编译super方法 // 但是一点都不好调试,可以考虑在其它模式下【如不想被别人调试的时候...】,使用这种编译 // 这里主要做实验,就不一一操作了 // fn[key] = Class.compileSuper(itemStr, key); // 放弃编译的方法,使用闭包 fn[key] = (function(key, proto){ return function(){ var tmp = this._super; // 这一句依赖后面的 fn.super = _super; this._super = this.super[key]; var res = item.apply(this, arguments); this._super = tmp; return res; }; })(key, item); }else{ fn[key] = item; } }else{ fn[key] = item; } }; // 可以通过super寻找到父类 fn.super = _super; myClass.extend = fn.extend = Class.extend; return myClass; };
因无法调试等原因,丢弃了匹配【重新编译字符串】的实现,使用了闭包。
但是闭包带来了额外的内存消耗,所以,如果真正上线,最好还是使用匹配的实现。
下面看两个例子:
var myFirst = Class.extend({ constroctor: myFirst, ctor: function(name){ // 因为父类Class,没有ctor方法,所以this._super(name);的调用,会报错 // this._super(name); console.log(name); } }); var mySecond = myFirst.extend({ ctor: function(name, age){ // 继承了myFirst,因为myFirst有ctor方法,所以,this._super(name)正常使用 this._super(name); console.log(age); } }); // 最终数据: var ss = new mySecond("da宗熊", 26); // 输出: da宗熊 26
代码看着挺优雅的,
但这种实现,也有一定的局限性:
1、约定了ctor为构造函数,new操作,实际调用了ctor的操作【可容忍】
2、继承没有筛选属性,会把父类的所有属性继承下来
3、链太深之后,会造成子类过度臃肿
个人觉得,较为简单的项目,是完全没必要使用的。
只有项目中,有强烈的上下级继承关系的时候,才是它发光发热的时候。
时间: 2024-11-08 09:13:21