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实现图片信息的浮动显示实例代码
Aug 28 Javascript
js如何调用qq互联api实现第三方登录
Mar 28 Javascript
浅谈javascript 归并方法
Jan 21 Javascript
jQuery+ajax+asp.net获取Json值的方法
Jun 08 Javascript
KnockoutJS 3.X API 第四章之数据控制流component绑定
Oct 10 Javascript
12 款 JS 代码测试必备工具(翻译)
Dec 13 Javascript
详解vue2.0组件通信各种情况总结与实例分析
Mar 22 Javascript
javascript按顺序加载运行js方法
Dec 01 Javascript
微信小程序实现星级评分和展示
Jul 05 Javascript
WebGL three.js学习笔记之阴影与实现物体的动画效果
Apr 25 Javascript
微信小程序tab切换可滑动切换导航栏跟随滚动实现代码
Sep 04 Javascript
vue+echarts+datav大屏数据展示及实现中国地图省市县下钻功能
Nov 16 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
php在linux下检测mysql同步状态的方法
2015/01/15 PHP
编写PHP脚本来实现WordPress中评论分页的功能
2015/12/10 PHP
php构造函数与析构函数
2016/04/23 PHP
IOS 开发之NSDictionary转换成JSON字符串
2017/08/14 PHP
半角全角相互转换的js函数
2009/10/16 Javascript
jquery图片上下tab切换效果
2011/03/18 Javascript
原生JavaScript生成GUID的实现示例
2014/09/05 Javascript
jQuery带时间的日期控件代码分享
2015/08/26 Javascript
jquery自定义插件——window的实现【示例代码】
2016/05/06 Javascript
JS中BOM相关知识点总结(必看篇)
2016/11/22 Javascript
vue动态组件实现选项卡切换效果
2017/03/08 Javascript
关于微信小程序登录的那些事
2019/01/08 Javascript
详解jQuery如何实现模糊搜索
2019/05/10 jQuery
js获取 gif 的帧数的代码实例
2019/09/10 Javascript
[01:15:12]DOTA2上海特级锦标赛主赛事日 - 1 败者组第一轮#4Newbee VS CDEC
2016/03/03 DOTA
Python交换变量
2008/09/06 Python
python中input()与raw_input()的区别分析
2016/02/27 Python
python数据结构之列表和元组的详解
2017/09/23 Python
jupyter notebook 中输出pyecharts图实例
2020/04/23 Python
Python 多线程其他属性以及继承Thread类详解
2019/08/28 Python
python-docx文件定位读取过程(尝试替换)
2020/02/13 Python
python正则表达式实例代码
2020/03/03 Python
html5实现多图片预览上传及点击可拖拽控件
2018/03/15 HTML / CSS
如何给HTML标签中的文本设置修饰线
2019/11/18 HTML / CSS
来自世界各地的优质葡萄酒:VineShop24
2018/07/09 全球购物
Chupi官网:在爱尔兰手工制作的订婚、结婚戒指和精美珠宝
2020/09/28 全球购物
Java中的基本数据类型所占存储空间大小固定的吗
2012/02/15 面试题
求职推荐信
2013/10/28 职场文书
银行职员思想汇报
2013/12/31 职场文书
JAVA程序员自荐书
2014/01/30 职场文书
安全生产活动月方案
2014/03/09 职场文书
如何写好建议书
2014/03/13 职场文书
公司离职证明范本(汇总)
2014/09/10 职场文书
华山导游词
2015/02/03 职场文书
python爬不同图片分别保存在不同文件夹中的实现
2021/04/02 Python
tomcat正常启动但网页却无法访问的几种解决方法
2022/05/06 Servers