很久没写博客了,突然想起 JS 的 OO 自己有一个想法,并实现了,于是就拿来作新博文的内容。

关于 JS 的 OO,这里有一份列表,均是我以前总结这方面的心得与体会,不正之处,应要提出。

  • JS OO继承、多态一法
  • JavaScript“类”继承的横向比较
  • 学习NodeJS第五天:JavaScript的继承
  • YUI 3中的继承模式及其用法简介
  • Ext.extend()中使用super关键字

纵观多少 JS OO 实现的方法,其内部总有些不足。我在项目试过的也有,一直以来不太满意。有什么不足和不满意?——我在过往的博文都有提了提……

本文所介绍的方法,立足于经典的 JS 类写法,对其扩充了重载方法(overload)之实现,而又仍然使用 JS prototype 原型继承的模式来处理继承的。因此,两个旧的用法(经典类写法与 prototype继承) 与一个新实现“重载”,则“重载”为该方法的亮点,其他之外并无甚特别之处。

一、如何封装?

首先说说经典的 JS 类写法。本方法中采用“经典”的类写法,也只能使用这写法,其他的写法均无效。所谓“经典”写法,就是我们最开始学习js时,通常教科书跟你说的那种写法(例子一):

function myClass(){// private local varialbiesvar localVar;// public variabiesthis.publicVar = 0;// private methodsfunction privateMethod(a){}// public methodthis.publicMethod = privateMethod; }

而不是修改原型对象的方法:

function myClass(){// private local varialbiesvar localVar;// private methodsfunction privateMethod(a){} } myClass.prototype = {// public variabiespublicVar : 0,// public methodpublicMethod : 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 varialbiesvar localVar;// private methodsfunction 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 queueif(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如是观相关推荐

  1. js OO写的一个键盘字母游戏

    今天用OO写了一个键盘字母的游戏,可以用于平常的键盘练习,写的不好的地方谢谢指出. 主要实现了效果: 1.实现了积分的累加: 2.积分到一定程度后升级: 3.当字母下落到一定程度的时候就游戏失败. 附 ...

  2. 君子当如是——观《孔子》有感

    二一年,十一月的十九号中午,看完了这部由周润发主演的电影<孔子>. 做做感想的记录吧 鲁定公,一开始信任孔子,将他从一介庶民提拔到代理相国.但在最后的内政统一之际,他怕了,他退缩了.也许其 ...

  3. 八款Js框架介绍及比较~转载

    Js框架介绍 目前来看,JS框架以及一些开发包和库类有如下几个,Dojo .Scriptaculous .Prototype .yui-ext .Jquery .Mochikit.mootools . ...

  4. 借鉴一些关于js框架的东西

    八款Js框架介绍及比较,Dojo .Scriptaculous .Prototype .yui-ext .Jquery .Mochikit.mootools .moo.fx,componentartu ...

  5. 偷偷修复漏洞 苹果要求研究员噤声

    1.偷偷修复漏洞 苹果要求研究员噤声 此前公布苹果0day漏洞PoC的研究员,如今伤口又被撒盐:前两天更新的iOS 15.0.2又"偷偷"修复了他之前提交的漏洞,而且和往常一样没有 ...

  6. 复习webpack4之Code Splitting

    之前学习过webpack3的知识,但是webpack4升级后还是有很多变动的,所以这次重新整理一下webpack4的知识点,方便以后复习. 这次学习webpack4不仅仅要会配置,记住核心API,最好 ...

  7. 读《构建之法》第四,十七章有感

    第四章 原文:函数最好有单一的出口,为了达到这一目的,可以使用goto.只要有助于程序逻辑的清晰体现,什么方法都可以使用,包括goto. 问题1:我们在写程序时,常常会存在两个return返回值,例如 ...

  8. 石头高墙怎么放_朱良志:古人对石头的审美

    在朱良志看来,石之美学,一在"丑怪",二在"真幻".丑而颠覆审美定规,怪而超脱秩序之外.而石之凿空穿眼,虚实相生,让人得以洞穿纷繁表象,抵达枯寂嶙峋的真实. 当 ...

  9. 《“己学”发略》发略

    己学 发略:简单讲 刍论:浅陋的议论 四善端:恻.羞.辞.是 四善德:仁.义.礼.智 文献 [1]麻尧宾."己学"发略:本体的综合构造与儒家的生命哲学[J].四川大学学报(哲学社会 ...

最新文章

  1. 剑指Offer - 面试题40. 最小的k个数(排序/大顶堆)
  2. 使用计算机绘制景物图像的两个主要步骤是,计算机11考试.doc
  3. 属猴的人2021年运势预测
  4. cpu —>内存—>硬盘这种方式是不是更慢?
  5. 大数据平台有什么功能作用
  6. 【python】Tkinter窗口可视化(二)
  7. BCD码和ASCII码的区别
  8. VIM python 自动补全插件:pydiction
  9. 2021年全球电力线通信(PLC)系统收入大约7385.8百万美元,预计2028年达到14530百万美元,2022至2028期间,年复合增长率CAGR为11.0%
  10. 图谱实战 | 开源知识图谱融合工具剖析:Dedupe与OpenEA工具实现思想、关键环节与实操分析...
  11. sendmail php qq垃圾邮件,发送邮件,被QQ定义为疑似垃圾邮件,如何解决这个有关问题...
  12. python输出n的32次方_在Python中,如何将2的32次方-1的值存放到g中?
  13. 关于VS运行时出现错误cannot decrement string iterator before begin
  14. 他一年开发19款!款款口碑爆棚
  15. Windows中Nginx下载、安装、配置
  16. Kaggle---Toxic Comment Classification Challenge
  17. TCP/IP协议栈Lwip的设计与实现:之一
  18. 今日睡眠质量记录73分
  19. USB Redirector(usb设备共享软件)官方正式版V6.12.0.3230 | USB共享软件下载 | usb redirector是什么软件
  20. Open-XML-SDK 如何实现更新Word中域的值

热门文章

  1. Windows 缺失msvcp140.dll文件
  2. e5运行Linux系统,CPU-Z 1.96更新介绍,可用Wine及deepin-wine5在Linux中运行
  3. Flash Socket 的基本通讯协议流程例子
  4. 逛画展(二分+队列)
  5. 企业微信SCRM的设计理念是什么?和CRM有什么不同?
  6. 全新原装STM32/GD32可能是假货
  7. UPS知识全集,值得收藏!
  8. 怎么做抖音故障艺术风格人物照片效果
  9. AI识别抑郁症正确率高达八成,但AI+精神健康还有很长的路要走
  10. R语言rjags使用随机效应进行臭氧数据分析