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 图片切换插件(代码比较少)
May 07 Javascript
javascript获取鼠标点击元素对象(示例代码)
Dec 20 Javascript
javascript创建函数的20种方式汇总
Jun 23 Javascript
js实现搜索框关键字智能匹配代码
Mar 26 Javascript
BootStrap 弹出层代码
Feb 09 Javascript
canvas实现十二星座星空图
Feb 14 Javascript
Vue指令的钩子函数使用方法
Mar 20 Javascript
HTML中使背景图片自适应浏览器大小实例详解
Apr 06 Javascript
微信小程序注册60s倒计时功能 使用JS实现注册60s倒计时功能
Aug 16 Javascript
mpvue中配置vuex并持久化到本地Storage图文教程解析
Mar 15 Javascript
移动端滑动切换组件封装 vue-swiper-router实例详解
Nov 25 Javascript
VUE子组件向父组件传值详解(含传多值及添加额外参数场景)
Sep 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
PHP有序表查找之二分查找(折半查找)算法示例
2018/02/09 PHP
PHP的mysqli_ssl_set()函数讲解
2019/01/23 PHP
PHP的mysqli_stmt_init()函数讲解
2019/01/24 PHP
PHP实现限制域名访问的实现代码(本地验证)
2020/09/13 PHP
Jquery数独游戏解析(一)-页面布局
2010/11/05 Javascript
Extjs实现进度条的两种便捷方式
2013/09/26 Javascript
用jquery统计子菜单的条数示例代码
2013/10/18 Javascript
鼠标滚轮改变图片大小的示例代码
2013/11/20 Javascript
js中判断用户输入的值是否为空的简单实例
2013/12/23 Javascript
淘宝网提供的国内NPM镜像简介和使用方法
2014/04/17 Javascript
基于NodeJS的前后端分离的思考与实践(四)安全问题解决方案
2014/09/26 NodeJs
移动适配的几种方案(三种方案)
2016/11/25 Javascript
JavaScript中${pageContext.request.contextPath}取值问题及解决方案
2016/12/08 Javascript
JS中Select下拉列表类(支持输入模糊查询)功能
2017/01/17 Javascript
微信小程序中form 表单提交和取值实例详解
2017/04/20 Javascript
解决Nodejs全局安装模块后找不到命令的问题
2018/05/15 NodeJs
[08:04]TI4西雅图DOTA2前线报道 海涛探访各路人马
2014/07/09 DOTA
python 输出一个两行字符的变量
2009/02/05 Python
Python使用win32com实现的模拟浏览器功能示例
2017/07/13 Python
Tensorflow中使用tfrecord方式读取数据的方法
2018/06/19 Python
5分钟 Pipenv 上手指南
2018/12/20 Python
Python魔法方法详解
2019/02/13 Python
详解python tkinter教程-事件绑定
2019/03/28 Python
Python自省及反射原理实例详解
2020/07/06 Python
python利用 keyboard 库记录键盘事件
2020/10/16 Python
css3 2D图片转动样式可以扩充到Js当中
2014/04/29 HTML / CSS
详解如何用HTML5 Canvas API控制图片的缩放变换
2016/03/22 HTML / CSS
英国婴儿产品专家:Samuel Johnston
2020/04/20 全球购物
诉讼代理人授权委托书
2014/04/08 职场文书
幼儿园六一亲子活动方案
2014/08/26 职场文书
工伤事故处理协议书怎么写
2014/10/15 职场文书
领导干部“四风”查摆问题个人整改措施
2014/10/28 职场文书
信息技术国培研修日志
2015/11/13 职场文书
浅谈mysql增加索引不生效的几种情况
2021/06/23 MySQL
如何解决php-fpm启动不了问题
2021/11/17 PHP
redis调用二维码时的不断刷新排查分析
2022/04/01 Redis