网上的众多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、链太深之后,会造成子类过度臃肿
个人觉得,较为简单的项目,是完全没必要使用的。
只有项目中,有强烈的上下级继承关系的时候,才是它发光发热的时候。