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对象、属性、事件手册集合方便查询
Jul 04 Javascript
最短的IE判断代码
Mar 13 Javascript
Javascript中arguments对象详解
Oct 22 Javascript
javascript遇到html5的一些表单属性
Jul 05 Javascript
JavaScript对Json的增删改属性详解
Jun 02 Javascript
用自定义图片代替原生checkbox实现全选,删除以及提交的方法
Oct 18 Javascript
利用jquery获取select下拉框的值
Nov 23 Javascript
JavaScript 实现 Tab 点击切换实例代码
Mar 25 Javascript
webpack v4 从dev到prd的方法
Apr 02 Javascript
JavaScrip数组去重操作实例小结
Jun 20 Javascript
React 实现车牌键盘的示例代码
Dec 20 Javascript
Node.js API详解之 Error模块用法实例分析
May 14 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使用array_rand()函数从数组中随机选择一个或多个元素
2014/04/28 PHP
Thinkphp微信公众号支付接口
2016/08/04 PHP
PHP将URL转换成短网址的算法分享
2016/09/13 PHP
php中输出json对象的值(实现方法)
2018/03/07 PHP
PHP学习笔记之session
2018/05/06 PHP
PHP PDOStatement::errorInfo讲解
2019/01/31 PHP
PHP 实现链式操作
2021/03/09 PHP
深入理解JavaScript系列(7) S.O.L.I.D五大原则之开闭原则OCP
2012/01/15 Javascript
JS对img标签进行优化使用onerror显示默认图像
2014/04/24 Javascript
Javascript 实现图片无缝滚动
2014/12/19 Javascript
jQuery插件实现适用于移动端的地址选择器
2016/02/18 Javascript
Javascript使用SWFUpload进行多文件上传
2016/11/16 Javascript
JS遍历对象属性的方法示例
2017/01/10 Javascript
docker中编译nodejs并使用nginx启动
2017/06/23 NodeJs
Vue.js最佳实践(五招助你成为vuejs大师)
2018/05/04 Javascript
node.js中TCP Socket多进程间的消息推送示例详解
2018/07/10 Javascript
微信小程序实现tab页面切换功能
2018/07/13 Javascript
Vue-Quill-Editor富文本编辑器的使用教程
2018/09/21 Javascript
vue-router权限控制(简单方式)
2018/10/29 Javascript
详解wepy开发小程序踩过的坑(小结)
2019/05/22 Javascript
JS Math对象与Math方法实例小结
2019/07/05 Javascript
详解webpack打包vue项目之后生成的dist文件该怎么启动运行
2019/09/06 Javascript
Vue 实现html中根据类型显示内容
2019/10/28 Javascript
Vue 实现监听窗口关闭事件,并在窗口关闭前发送请求
2020/09/01 Javascript
MAC中PyCharm设置python3解释器
2017/12/15 Python
Python使用Django实现博客系统完整版
2020/09/29 Python
Python实用技巧之列表、字典、集合中根据条件筛选数据详解
2018/07/11 Python
利用Python实现学生信息管理系统的完整实例
2020/12/30 Python
美国最灵活的移动提供商:Tello
2017/07/18 全球购物
党员干部承诺书
2014/03/25 职场文书
中药学专业求职信
2014/05/31 职场文书
生日宴会策划方案
2014/06/03 职场文书
大学生学雷锋活动总结
2014/06/26 职场文书
少先队辅导员事迹材料
2014/12/24 职场文书
中班下学期个人总结
2015/02/12 职场文书
php远程请求CURL案例(爬虫、保存登录状态)
2021/04/01 PHP