我的JS OO如是观
来源:互联网 发布:人工智能的应用实例 编辑:程序博客网 时间:2024/05/01 05:14
关于JS的OO,这里有一份列表,均是我以前总结这方面的心得与体会,不正之处,应要提出。
- JS OO继承、多态一法
- JavaScript“类”继承的横向比较
- 学习NodeJS第五天:JavaScript的继承
- YUI 3中的继承模式及其用法简介
- Ext.extend()中使用super关键字
纵观多少JS OO实现的方法,其内部总有些不足。我在项目试过的也有,一直以来不太满意。有什么不足和不满意?——我在过往的博文都有提了提……
本文所介绍的方法,立足于经典的JS类写法,对其扩充了重载方法(overload)之实现,而又仍然使用JSprototype原型继承的模式来处理继承的。因此,两个旧的用法(经典类写法 与 prototype继承) 与一个新实现“重载”,则“重载”为该方法的亮点,其他之外并无甚特别之处。
一、如何封装?
首先说说经典的JS类写法。本方法中采用“经典”的类写法,也只能使用这写法,其他的写法均无效。所谓“经典”写法,就是我们最开始学习js时,通常教科书跟你说的那种写法(例子一):
- function myClass(){
- // private local varialbies
- var localVar;
- // public variabies
- this.publicVar = 0;
- // private methods
- function privateMethod(a){
- }
- // public method
- this.publicMethod = privateMethod;
- }
而不是修改原型对象的方法:
- function myClass(){
- // private local varialbies
- var localVar;
- // private methods
- function privateMethod(a){
- }
- }
- myClass.prototype = {
- // public variabies
- publicVar : 0,
- // public method
- publicMethod : function (a){
- }
- };
貌似现在越来越少人采用第一种也就是经典的写法。难道这是要突出JS“原型继承”的本质才推崇第二种写法的吗?不得而知,总之大家喜欢就是了。但在本文介绍的JS OO继承方法中,却一律采用第一种也就是经典的写法。这样子,比较像Java的类哦~呵呵。
再讲一下“例子一”部分。类myClass中,注释private local variablies所指为私有内部变量,以“var”开头则外界不可以访问,反之,通过this分配的变量或方法,则可为外界所访问。请注意this.publicMehtod = privateMethod这里,无论私有方法还是公有方法,均指向同一个函数。当然,这里举的是特例,一般我们还是拆分来写。
把代码写成类就是为了更好地封装,形成API供调用。到这里我们明确封装方式为经典的JS类写法,紧接着,就是继承。
二、如何继承?
JS只有一种继承方式,就是原型继承。设有两个类,base基类和son子类,son类是base类的派生类。这样完成了一次继承:
- base = new base;
- son.prototype = base; // 原型继承!
每定义一次新类,都会保存父类其实例的拷贝。父类对于子类来说,都是唯一的。上述过程非常简单,但是下面我给出的方案中,会稍微复杂一些,加入一个superObjs的数组,数组保存所有父类。代码如下:
- base = new base;
- if(!base.superObjs){
- base.superObjs = [base];
- }else{
- base.superObjs.push(base);
- }
- son.prototype = base; // 原型继承!
加入superObjs的数组有什么用途?这里按下不表,权作一伏笔,后面有用。
到这里整体上依然没有任何新意。究竟我们在干什么?呵呵,当然接下来就要揭示问题的所在了。
经典封装、继承的写法有一个很大的问题,就不允许方法的重载,简单说,就是后面的类,相同名称的方法会覆盖的原来前面类相同名称的方法。覆盖的这一时刻发生在new 子类()的时候。
浮现出了这个问题,应该如何解决?还是有办法的。请见下列源码:
- // 访问父类的内部函数
- // written by Frank Cheung
- function _super(){
- var
- byExplicit = arguments[0]
- ,byExplicit = byExplicit && byExplicit.length && byExplicit.callee
- // if explicit, it means arguments.caller === arguments(old) // true!
- // if not explicit, it means get Method by arguments.caller.callee.
- ,overrided = byExplicit ? arguments[0] : arguments.caller.callee
- ,memberName // 成员名称一直不变的。名称字符串其作为查询成员的凭据。
- ,superMember // 找到的超类成员
- ,superObjs = this.superObjs // 父类列表
- ,superObj // 当前父类(不一定是目标父类)
- ,args = byExplicit ? Array.prototype.slice.call(arguments, 1) : arguments;
- if(!overrided){
- debugger;
- Error.throwErr({
- msg : "必须输入args对象!"
- ,method : arguments.callee
- });
- }
- // 先找到成员名称。
- for(var i in this){
- if(this[i] == overrided){
- memberName = i;
- }
- }
- for(var i = 0, j = superObjs.length; i < j; --j){
- superObj = superObjs[j - 1];
- superMember = superObj[memberName];
- if(superMember){
- return typeof superMember == 'function'
- ? superMember.apply(this, args)
- : superMember
- }
- }
- if(!superMember){
- for(var i = 0, j = superObjs.length; i < j; i++){
- superObj = superObjs[i];
- for(methodName in superObj){
- if(superObj[methodName] == overrided){
- superMember = superObjs[i-1][methodName];
- return superMember.apply(this, args);
- }
- }
- }
- }
- throw '如果走到这一步,说明super()失败!';
- }
前面所说的“伏笔”就是为了方法重载而设的。受时间所限,今日先帖帖源码,容小弟日后再添教程详述之(有新念头,旧想法被推翻。)。
三、如何多态?
多态即多继承。然而多态的问题,我尚未作深入调查。只是知道有一点,用fn.apply/call的方法可以强制指定this对象指针,所以用来作多态亦未尝不可,即:
- function A_Class(){
- // private local varialbies
- var localVar;
- // private methods
- function privateMethod(a){
- }
- }
- function B_Class(){
- A_Class.call(this); // A_Class 内部的 this 变为当前 B_Class 实例。
- this.foo = function(){
- }
- }
若说这就是“多态”,可能很多人都会觉得牵强,——我也同意,但我仍认为,这是一个比较便捷的方法,算是一个思路。但仍觉得作为真正的多态来说,还是不太贴切,有待进一步的研究吧。
附继承方法的完整代码:
- /**
- * 继承。
- * @param {Function} son 子类
- * @param {Function} base 父类
- */
- Object.extend = (function(){
- function _super(){
- var
- byExplicit = arguments[0]
- ,byExplicit = byExplicit && byExplicit.length && byExplicit.callee
- // if explicit, it means arguments.caller === arguments(old) // true!
- // if not explicit, it means get Method by arguments.caller.callee.
- ,overrided = byExplicit ? arguments[0] : arguments.caller.callee
- ,memberName // 成员名称一直不变的。名称字符串其作为查询成员的凭据。
- ,superMember // 找到的超类成员
- ,superObjs = this.superObjs // 父类列表
- ,superObj // 当前父类(不一定是目标父类)
- ,args = byExplicit ? Array.prototype.slice.call(arguments, 1) : arguments;
- if(!overrided){
- debugger;
- Error.throwErr({
- msg : "必须输入args对象!"
- ,method : arguments.callee
- });
- }
- // 先找到成员名称。
- for(var i in this){
- if(this[i] == overrided){
- memberName = i;
- }
- }
- for(var i = 0, j = superObjs.length; i < j; --j){
- superObj = superObjs[j - 1];
- superMember = superObj[memberName];
- if(superMember){
- return typeof superMember == 'function'
- ? superMember.apply(this, args)
- : superMember
- }
- }
- if(!superMember){
- for(var i = 0, j = superObjs.length; i < j; i++){
- superObj = superObjs[i];
- for(methodName in superObj){
- if(superObj[methodName] == overrided){
- superMember = superObjs[i-1][methodName];
- return superMember.apply(this, args);
- }
- }
- }
- }
- throw '如果走到这一步,说明super()失败!';
- }
- var queue = [];
- var timer = 0;
- function delayInherit(item){
- var son = item[0], base = item[1];
- Object.extend(son, base);
- // ok, it's done!
- debugger;
- // alert(typeof base)
- }
- function addQueue(son, base){
- queue.push([son, base]);
- // if(!timer){
- // timer = setTimeout(function(){
- // Array.each(queue, delayInherit, queue);
- // }, 2500 /* 这是一个模拟值,不精确 */ );
- //
- // }
- }
- return function(son, base){
- // @todo if not loaded, add to queue
- if(base && typeof(base) != 'function'){
- addQueue(son, base);
- return;
- }
- base = new base;
- if(!base._super){
- base._super = _super;
- }
- if(!base.superObjs){
- base.superObjs = [base];
- }else{
- base.superObjs.push(base);
- }
- son.prototype = base; // 原型继承!
- }
- })();
- 我的JS OO如是观
- 我的JS OO如是观
- 我的OO观
- JS OO 的继承机制
- 花有花的芬芳,人如是
- 计算机如是何启动的?
- OO --- JS
- 如是使用JS实现页面内容随机显示
- 我出的几道OO面试题
- js-oo(1)
- OO --- JS 2
- JS OO继承、多态
- Js OO方法小记
- JS OO模板
- js OO写的一个键盘字母游戏
- 师傅热土上如是如是如是
- 抓不抓得住的幸福上帝如是问
- 每天如是
- nginx queue
- libusb 介绍
- 2011年11月垂直文学网站行业数据
- win7 Host 与virtualbox 中的 ubuntu 11.10 共享文件夹
- 乔布斯在斯坦福大学2005年毕业典礼上的演讲
- 我的JS OO如是观
- Android 网络编程之 Http 通信
- VC单选按钮控件(Radio Button)用法
- Struts2与Struts1的比较摘录整理
- 深入分析C++中char * 和char []的区别
- JS OO继承、多态
- [USB] 梳理USB子系统
- VS高级调试技巧 转自CodeProject (http://www.codeproject.com/KB/debug/Advanced_Debugging.aspx)
- magento项目中使用多个数据库的方法