SmartJS2.0加入OOP的功能。OOP包括klass与factory两个对象。
Klass 类继承
与其他的类继承相比,smartjs使用了执行指针的概念(后面例子中会介绍),另外提供base基类和初始化控制的扩展功能。
首先来看看接口:
var _klass = st.klass(name, prop, parent, config); //new _klass() 与 _klass()效果相同,实现了自初始化功能更 var obj = new _klass();
name : 类名
prop : 类属性&方法
parent :[可选],父类对象
config :[可选],类配置参数,做动态扩展使用;后续版本会加入内容;
注意自初始化方法为:klassInit,在实例化时执行
实例化类后,对象会具有以下方法和属性:
//获取基类对象
obj.getBase(baseName);
//执行基类对象
obj.callBase(fnName, baseName, args);
//对象扩展方法
obj.extend(prop);
//父类对象
obj._$super
//类标示
obj._$klass : bool
//类名
obj._$kName : string
//继承链
obj._$inheirts : array
此外两种全局扩展方式:
1. 基于原形链的基类扩展,使用st.conf('oop-KlassBase'),可以取到基类对象进行扩展
2. 在类初始化时,对实例化的对象进行扩展,可以使用st.onKlassInit对象进行添加扩展方法。
st.onKlassInit 是promiseEvent对象,参数为:obj,conf
obj:类对象
conf:即klass定义的时候的conf
代码示例
基础
var user = st.klass("user", { klassInit: function(name) { this.name = name; }, say: function(text) { return this.name + ',' + text; } }); var user1 = new user('roy'), //执行方法与实例化等效 user2 = user('tracy'); expect(user1.name).toBe('roy'); expect(user1.say('hello')).toBe('roy,hello'); expect(user2.name).toBe('tracy'); expect(user2.say('hello')).toBe('tracy,hello');
综合例子
var user1 = st.klass("user1", { name: 'user1', //自初始化方法为:klassInit,在实例化时执行 klassInit: function() {} }, user); //继承测试 it("inheirt", function() { var roy = user1('roy'); expect(roy.name).toBe('user1'); expect(roy.say('hello')).toBe('user1,hello'); }) //调用父类测试 it("klassBase - callBase", function() { var roy = user1(); roy.callBase('klassInit', ['roy']); expect(roy.name).toBe('roy'); }) //扩展例子 it("klassBase - extend", function() { var roy = user1(); roy.extend({ say: function() { return "extend"; } }); expect(roy.say()).toBe('extend'); expect(roy.callBase('say', ['extend'])).toBe("user1,extend"); })
多级继承例子。在多级继承中有一种场景每个子类方法都会调用父类的方法,而方法中又会使用到当前对象的属性,则问题就来了;
如果是采用的parent.xxx然后传递this下的属性值过去,则没太大的问题。backbone就采用的这种。
另外像base.js直接改写原始方法,将父对象封入闭包中,也无问题。只是这种限制比较大,只能调用父类的同名方法。
而dojo采用的是this.parent.xxx.call(this)的方式,则就会悲剧了,死循环就来了。
导致这样的原因就是将this带入parent方法后,父类又执行this.parent。而这是this则是子类的对象,那么方法就只会不停的调用parent的方法。
有兴趣的朋友可以下去看下,项目上面使用的继承会出现此问题。如果有更好的方案,希望能分享。
smart采用类继承的方式与dojo比较类似,但是调用父类方法由callBae这个方法来代理,同时使用指针来记录方法的执行轨迹,这样保证了从子到根的各级调用。
var user = st.klass("user", { klassInit: function(name) { this.name = name; }, say: function(text) { return this.name + ',' + text; } }) var user2 = st.klass('user2', { say: function(text) { return this.callBase('say', [text]) + "-lv2"; } }, user); var user3 = st.klass('user3', { say: function(text) { return this.callBase('say', [text]) + "-lv3"; } }, user2); var user4 = st.klass('user4', { say: function(text) { return this.callBase('say', [text]) + "-lv4"; } }, user3); var roy = new user4('roy'); expect(roy._$inheirts + '').toBe('user4,user3,user2,user'); //依次执行到根,正确将当前的this对象的值输出 expect(roy.say('hello')).toBe('roy,hello-lv2-lv3-lv4'); //从3级开始执行 expect(roy.callBase('say', ['hello'])).toBe("roy,hello-lv2-lv3"); //指定从user开始执行 expect(roy.callBase('say', 'user', ['hello'])).toBe("roy,hello"); //上向略过2级执行 expect(roy.callBase('say', 2, ['hello'])).toBe("roy,hello-lv2");