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 相关文章推荐
javascript 时间比较实现代码
Oct 28 Javascript
打豆豆小游戏 用javascript编写的[打豆豆]小游戏
Jan 08 Javascript
JS 加入收藏夹的代码(主流浏览器通用)
May 13 Javascript
AngularJS基础 ng-model-options 指令简单示例
Aug 02 Javascript
AngularJS入门教程之过滤器详解
Aug 19 Javascript
深入理解React Native原生模块与JS模块通信的几种方式
Jul 24 Javascript
View.post() 不靠谱的地方你知道多少
Aug 29 Javascript
JavaScript中数组常见操作技巧
Sep 01 Javascript
基于JavaScript实现瀑布流布局
Aug 15 Javascript
小程序云开发实战小结
Oct 25 Javascript
Vue项目报错:Uncaught SyntaxError: Unexpected token
Nov 10 Javascript
JavaScript实现刮刮乐效果
Nov 01 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
改德生G88 - 加装等响度低音提升电路
2021/03/02 无线电
支持oicq头像的留言簿(一)
2006/10/09 PHP
MySQL连接数超过限制的解决方法
2011/07/17 PHP
php&mysql 日期操作小记
2012/02/27 PHP
PHP获取指定函数定义在哪个文件中以及其所在的行号实例
2014/05/08 PHP
php单例模式的简单实现方法
2016/06/10 PHP
js 模拟实现类似c#下的hashtable的简单功能代码
2010/01/24 Javascript
Jquery中获取iframe的代码
2011/01/11 Javascript
jquery弹窗插件colorbox绑定动态生成元素的方法
2014/06/20 Javascript
JavaScript获取网页表单提交方式的方法
2015/04/02 Javascript
详解JavaScript表单验证(E-mail 验证)
2016/03/31 Javascript
基于javascript bootstrap实现生日日期联动选择
2016/04/07 Javascript
js判断是否为空和typeof的用法(详解)
2016/10/07 Javascript
BootStrap+Mybatis框架下实现表单提交数据重复验证
2017/03/23 Javascript
React 使用browserHistory项目访问404问题解决
2018/06/01 Javascript
JS实现checkbox互斥(单选)功能示例
2019/05/04 Javascript
layui表单验证select下拉框实现验证的方法
2019/09/05 Javascript
小程序点击图片实现png转jpg
2019/10/22 Javascript
Element InputNumber计数器的使用方法
2020/07/27 Javascript
详解JavaScript 高阶函数
2020/09/14 Javascript
[53:15]2018DOTA2亚洲邀请赛3月29日 小组赛A组 KG VS OG
2018/03/30 DOTA
Python中操作MySQL入门实例
2015/02/08 Python
Python求解平方根的方法
2015/03/11 Python
Python基于list的append和pop方法实现堆栈与队列功能示例
2017/07/24 Python
对python中使用requests模块参数编码的不同处理方法
2018/05/18 Python
python实现网页自动签到功能
2019/01/21 Python
Python 如何反方向迭代一个序列
2020/07/28 Python
pycharm进入时每次都是insert模式的解决方式
2021/02/05 Python
Engel & Bengel官网:婴儿推车、儿童房家具和婴儿设备
2019/12/28 全球购物
历史学专业推荐信
2013/11/06 职场文书
医学生个人求职信范文
2014/02/07 职场文书
生活小常识广播稿
2014/09/16 职场文书
采购员岗位职责
2015/02/03 职场文书
教师专业技术工作总结2015
2015/05/13 职场文书
2016优秀毕业生个人事迹材料
2016/02/29 职场文书
redis实现排行榜功能
2021/05/24 Redis