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 相关文章推荐
Extjs 3.3切换tab隐藏相应工具栏出现空白解决
Apr 02 Javascript
JavaScript1.6数组新特性介绍以及JQuery的几个工具方法
Dec 06 Javascript
在页面中输出当前客户端时间javascript实例代码
Mar 02 Javascript
Bootstrap模态框使用详解
Feb 15 Javascript
jQuery实现搜索页面关键字的功能
Feb 16 Javascript
JavaScript实现两个select下拉框选项左移右移
Mar 09 Javascript
深入理解js 中async 函数的含义和用法
May 13 Javascript
JS实现判断图片是否加载完成的方法分析
Jul 31 Javascript
Javascript读写cookie的实例源码
Mar 16 Javascript
Vue2.0 实现页面缓存和不缓存的方式
Nov 12 Javascript
.netcore+vue 实现压缩文件下载功能
Sep 24 Javascript
微信小程序tab左右滑动切换功能的实现代码
Feb 08 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导入Excel到MySQL的方法
2011/04/23 PHP
PHP常用的文件操作函数经典收藏
2013/04/02 PHP
wordpress自定义url参数实现路由功能的代码示例
2013/11/28 PHP
php常用字符串String函数实例总结【转换,替换,计算,截取,加密】
2016/12/07 PHP
浅谈PHP中pack、unpack的详细用法
2018/03/12 PHP
php5.6.x到php7.0.x特性小结
2019/08/17 PHP
javascript add event remove event
2008/04/07 Javascript
JS 时间显示效果代码
2009/08/23 Javascript
使用apply方法处理数组的三个技巧[译]
2012/09/20 Javascript
js中call与apply的用法小结
2013/12/28 Javascript
jquery form表单序列化为对象的示例代码
2014/03/05 Javascript
js判断鼠标左、中、右键哪个被点击的方法
2015/01/27 Javascript
jQuery数组处理函数整理
2016/08/03 Javascript
js控制按钮,防止频繁点击响应的实例
2017/02/15 Javascript
jQuery模拟html下拉多选框的原生实现方法示例
2019/05/30 jQuery
D3.js 实现带伸缩时间轴拓扑图的示例代码
2020/01/20 Javascript
基于Vue的侧边目录组件的实现
2020/02/05 Javascript
基于react项目打包css引用路径错误解决方案
2020/10/28 Javascript
[01:12]DOTA2 2015年秋季互动指南
2015/11/10 DOTA
python冒泡排序简单实现方法
2015/07/09 Python
Python中使用asyncio 封装文件读写
2016/09/11 Python
Python小工具之消耗系统指定大小内存的方法
2018/12/03 Python
Python3之乱码\xe6\x97\xa0\xe6\xb3\x95处理方式
2020/05/11 Python
纯CSS3代码实现switch滑动开关按钮效果
2016/08/30 HTML / CSS
HTML5之WebGL 3D概述(上)—WebGL原生开发开启网页3D渲染新时代
2013/01/31 HTML / CSS
html5使用canvas画三角形
2014/12/15 HTML / CSS
DC Shoes澳大利亚官方网上商店:购买DC鞋子
2019/10/25 全球购物
企业为何需要商业计划书
2013/12/26 职场文书
给男朋友的道歉信
2014/01/12 职场文书
善意的谎言事例
2014/02/15 职场文书
团队精神口号
2014/06/06 职场文书
计算机毕业生自荐信
2014/06/12 职场文书
小学教研工作总结2015
2015/05/13 职场文书
导游词之唐山景点
2019/12/18 职场文书
python opencv通过4坐标剪裁图片
2021/06/05 Python
如何利用golang运用mysql数据库
2022/03/13 Golang