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中的$(document).ready()与window.onload的区别
Nov 18 Javascript
Extjs列表详细信息窗口新建后自动加载解决方法
Apr 02 Javascript
细说浏览器特性检测(2)-通用事件检测
Nov 05 Javascript
jquery获取对象的方法足以应付常见的各种类型的对象
May 14 Javascript
JavaScript版的TwoQueues缓存模型
Dec 29 Javascript
简介AngularJS中使用factory和service的方法
Jun 17 Javascript
JavaScript与ActionScript3两者的同性与差异性
Sep 22 Javascript
js放到head中失效的原因与解决方法
Mar 07 Javascript
Vue input控件通过value绑定动态属性及修饰符的方法
May 03 Javascript
r.js来合并压缩css文件的示例
Apr 26 Javascript
vue使用ajax获取后台数据进行显示的示例
Aug 09 Javascript
jQuery实现的页面弹幕效果【测试可用】
Aug 17 jQuery
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
ThinkPHP缓存方法S()概述
2014/06/13 PHP
PHP+iFrame实现页面无需刷新的异步文件上传
2014/09/16 PHP
朋友网关于QQ相关的PHP代码(研究QQ的绝佳资料)
2015/01/26 PHP
图文介绍PHP添加Redis模块及连接
2015/07/28 PHP
学习php设计模式 php实现享元模式(flyweight)
2015/12/07 PHP
php实现微信支付之现金红包
2018/05/30 PHP
Javascript & DHTML 实例编程(教程)(三)初级实例篇1—上传文件控件实例
2007/06/02 Javascript
javascript引导程序
2008/10/26 Javascript
js滚动条回到顶部的代码
2011/12/06 Javascript
电子商务网站上的常用的js放大镜效果
2011/12/08 Javascript
仿新浪微博返回顶部的jquery实现代码
2012/10/01 Javascript
Javascript验证上传图片大小[前台处理]
2014/07/18 Javascript
JavaScript Serializer序列化时间处理示例
2014/07/31 Javascript
jQuery插件scroll实现无缝滚动效果
2015/04/27 Javascript
获取IE浏览器Cookie信息的方法
2017/01/23 Javascript
前端自动化开发之Node.js的环境搭建教程
2017/04/01 Javascript
Vue实现购物车场景下的应用
2017/11/27 Javascript
JS加密插件CryptoJS实现AES加密操作示例
2018/08/16 Javascript
微信小程序自定义导航栏实例代码
2019/04/05 Javascript
微信小程序在线客服自动回复功能(基于node)
2019/07/03 Javascript
[01:45]2014DOTA2 TI预选赛预选赛 战前探营!
2014/05/21 DOTA
[02:19]DOTA2上海特级锦标赛 观赛指南 Spectator Guide
2016/02/04 DOTA
Python中的魔法方法深入理解
2014/07/09 Python
如何处理Python3.4 使用pymssql 乱码问题
2016/01/08 Python
对python中的for循环和range内置函数详解
2018/04/17 Python
django请求返回不同的类型图片json,xml,html的实例
2018/05/22 Python
python数据处理 根据颜色对图片进行分类的方法
2018/12/08 Python
使用python批量化音乐文件格式转换的实例
2019/01/09 Python
css3简单练习实现遨游浏览器logo的绘制
2013/01/30 HTML / CSS
CSS3 清除浮动的方法示例
2018/06/01 HTML / CSS
Linux常见面试题
2013/03/18 面试题
电脑教师的教学自我评价
2013/11/26 职场文书
《海伦?凯勒》教学反思
2014/04/17 职场文书
珍惜时间演讲稿
2014/05/14 职场文书
领导班子四风问题对照检查材料
2014/09/27 职场文书
2014年计划生育协会工作总结
2014/11/14 职场文书