JavaScript代码复用模式实例分析


Posted in Javascript onDecember 02, 2012

任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量避免使用这些模式,因为或多或少有带来一些问题;第二排是推荐篇,指的是推荐大家使用的模式,一般不会有什么问题。

模式1:默认模式
代码复用大家常用的默认模式,往往是有问题的,该模式使用Parent()的构造函数创建一个对象,并且将该对象赋值给Child()的原型。我们看一下代码:

function inherit(C, P) { C.prototype = new P();} 
// 父构造函数function Parent(name) { this.name = name || 'Adam';} 
// 给原型添加say功能Parent.prototype.say = function () { return this.name;}; 
// Child构造函数为空function Child(name) {} 
// 执行继承inherit(Child, Parent);var kid = new Child();console.log(kid.say()); 
// "Adam"var kiddo = new Child();kiddo.name = "Patrick";console.log(kiddo.say()); 
// "Patrick"// 缺点:不能让参数传进给Child构造函数var s = new Child('Seth');console.log(s.say()); 
// "Adam"这种模式的缺点是Child不能传进参数,基本上也就废了。

模式2:借用构造函数
该模式是Child借用Parent的构造函数进行apply,然后将child的this和参数传递给apply方法:

// 父构造函数function Parent(name) { this.name = name || 'Adam';} 
// 给原型添加say功能Parent.prototype.say = function () { return this.name;}; 
// Child构造函数function Child(name) { Parent.apply(this, arguments);}var kid = new Child("Patrick");console.log(kid.name); 
// "Patrick"// 缺点:没有从构造函数上继承say方法console.log(typeof kid.say); 
// "undefined"缺点也很明显,say方法不可用,因为没有继承过来。

模式3:借用构造函数并设置原型
上述两个模式都有自己的缺点,那如何把两者的缺点去除呢,我们来尝试一下:
// 父构造函数function Parent(name) { this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () { return this.name;};// Child构造函数function Child(name) { Parent.apply(this, arguments);}Child.prototype = new Parent();var kid = new Child("Patrick");console.log(kid.name); // "Patrick"console.log(typeof kid.say); // functionconsole.log(kid.say()); // Patrickconsole.dir(kid);delete kid.name;console.log(kid.say()); // "Adam"运行起来,一切正常,但是有没有发现,Parent构造函数执行了两次,所以说,虽然程序可用,但是效率很低。

模式4:共享原型
共享原型是指Child和Parent使用同样的原型,代码如下:

function inherit(C, P) { C.prototype = P.prototype;} 
// 父构造函数function Parent(name) { this.name = name || 'Adam';} 
// 给原型添加say功能Parent.prototype.say = function () { return this.name;}; 
// Child构造函数function Child(name) {}inherit(Child, Parent);var kid = new Child('Patrick');console.log(kid.name); 
// undefinedconsole.log(typeof kid.say); 
// functionkid.name = 'Patrick';console.log(kid.say()); 
// Patrickconsole.dir(kid);确定还是一样,Child的参数没有正确接收到。

模式5:临时构造函数
首先借用构造函数,然后将Child的原型设置为该借用构造函数的实例,最后恢复Child原型的构造函数。代码如下:

/* 闭包 */var inherit = (function () { var F = function () { }; return function (C, P) { F.prototype = P.prototype; C.prototype = new F(); C.uber = P.prototype; CC.prototype.constructor = C; }} ());function Parent(name) { this.name = name || 'Adam';}// 给原型添加say功能Parent.prototype.say = function () { return this.name;};// Child构造函数function Child(name) {}inherit(Child, Parent);var kid = new Child();console.log(kid.name); // undefinedconsole.log(typeof kid.say); // functionkid.name = 'Patrick';console.log(kid.say()); // Patrickvar kid2 = new Child("Tom");console.log(kid.say()); console.log(kid.constructor.name); // Childconsole.log(kid.constructor === Parent); // false问题照旧,Child不能正常接收参数。 模式6:klass 
这个模式,先上代码吧: 
var klass = function (Parent, props) { var Child, F, i; // 
1. // 新构造函数 Child = function () { if (Child.uber && Child.uber.hasOwnProperty("__construct")) { Child.uber.__construct.apply(this, arguments); } if (Child.prototype.hasOwnProperty("__construct")) { Child.prototype.__construct.apply(this, arguments); } }; // 
2. // 继承 ParentParent = Parent || Object; F = function () { }; F.prototype = Parent.prototype; Child.prototype = new F(); Child.uber = Parent.prototype; ChildChild.prototype.constructor = Child; / 
3. // 添加实现方法 for (i in props) { if (props.hasOwnProperty(i)) { Child.prototype[i] = props[i]; } } 
// return the "class" return Child;};var Man = klass(null, { __construct: function (what) { console.log("Man's constructor"); this.name = what; }, getName: function () { return this.name; }});var first = new Man('Adam'); 
// logs "Man's constructor"first.getName(); 
// "Adam"var SuperMan = klass(Man, { __construct: function (what) { console.log("SuperMan's constructor"); }, getName: function () { var name = SuperMan.uber.getName.call(this); return "I am " + name; }});var clark = new SuperMan('Clark Kent');clark.getName(); 
// "I am Clark Kent"console.log(clark instanceof Man); 
// trueconsole.log(clark instanceof SuperMan);

看着是不是有点晕,说好点,该模式的语法和规范拧得和别的语言一样,你愿意用么?

总结
以上六个模式虽然在某种特殊情况下实现了某些功能,但是都存在各自的缺点,所以一般情况,大家要避免使用。

Javascript 相关文章推荐
jQuery总体架构的理解分析
Mar 07 Javascript
JavaScript高级程序设计 事件学习笔记
Sep 10 Javascript
用JQuery实现表格隔行变色和突出显示当前行的代码
Feb 10 Javascript
js不能跳转到上一页面的问题解决方法
Mar 01 Javascript
Javascript玩转继承(三)
May 08 Javascript
JS实现在页面随时自定义背景颜色的方法
Feb 27 Javascript
JS实现根据用户输入分钟进行倒计时功能
Nov 14 Javascript
jquery.validate表单验证插件使用详解
Jun 21 jQuery
实例详解JavaScript中setTimeout函数的执行顺序
Jul 12 Javascript
在vue项目创建的后初始化首次使用stylus安装方法分享
Jan 25 Javascript
详解服务端预渲染之Nuxt(介绍篇)
Apr 07 Javascript
React Native项目框架搭建的一些心得体会
May 28 Javascript
JSONP 跨域访问代理API-yahooapis实现代码
Dec 02 #Javascript
script标签属性type与language使用选择
Dec 02 #Javascript
JavaScript中valueOf函数与toString方法深入理解
Dec 02 #Javascript
json对象转字符串如何实现
Dec 02 #Javascript
javascript 构造函数强制调用经验总结
Dec 02 #Javascript
js精度溢出解决方案
Dec 02 #Javascript
JavaScript词法作用域与调用对象深入理解
Nov 29 #Javascript
You might like
JS 网站性能优化笔记
2011/05/24 PHP
深入PHP数据缓存的使用说明
2013/05/10 PHP
PHP概率计算函数汇总
2015/09/13 PHP
代码生成器 document.write()
2007/04/15 Javascript
JQuery中each()的使用方法说明
2010/08/19 Javascript
Javascript 按位与赋值运算符 (&=)使用介绍
2014/02/04 Javascript
js调试系列 控制台命令行API使用方法
2014/06/18 Javascript
jQuery实现仿QQ空间装扮预览图片的鼠标提示效果代码
2015/10/30 Javascript
浅析JS获取url中的参数实例代码
2016/06/14 Javascript
seajs学习教程之基础篇
2016/10/20 Javascript
详解JavaScript的内置对象
2016/12/07 Javascript
Bootstrap CSS布局之代码
2016/12/17 Javascript
Angular.js指令学习中一些重要属性的用法教程
2017/05/24 Javascript
Vue.js实现价格计算器功能
2020/03/30 Javascript
JS实现带动画的回到顶部效果
2017/12/28 Javascript
详解vue通过NGINX部署在子目录或者二级目录实践
2018/09/03 Javascript
微信小程序页面间传值与页面取值操作实例分析
2019/04/30 Javascript
Vue初始化中的选项合并之initInternalComponent详解
2020/06/11 Javascript
[01:03:36]Ti4 循环赛第三日DK vs Titan
2014/07/12 DOTA
java直接调用python脚本的例子
2014/02/16 Python
从零学python系列之浅谈pickle模块封装和拆封数据对象的方法
2014/05/23 Python
Python导入模块时遇到的错误分析
2017/08/30 Python
Django项目中包含多个应用时对url的配置方法
2018/05/30 Python
Python多进程池 multiprocessing Pool用法示例
2018/09/07 Python
matplotlib命令与格式之tick坐标轴日期格式(设置日期主副刻度)
2019/08/06 Python
python数据类型之间怎么转换技巧分享
2019/08/20 Python
python 爬虫百度地图的信息界面的实现方法
2019/10/27 Python
python中的逆序遍历实例
2019/12/25 Python
详解Python openpyxl库的基本应用
2021/02/26 Python
美国婴儿服装购物网站:Gerber Childrenswear
2020/05/06 全球购物
公司活动方案范文
2014/03/06 职场文书
总经理检讨书
2014/09/15 职场文书
群众路线教育实践活动自我剖析思想汇报
2014/10/04 职场文书
大学生考试作弊检讨书1000字
2014/10/14 职场文书
原来闭幕词是这样写的呀!
2019/07/01 职场文书
Python绘画好看的星空图
2022/03/17 Python