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 getElementsByClassName实现代码
Oct 11 Javascript
从零开始学习jQuery (十) jQueryUI常用功能实战
Feb 23 Javascript
通过jQuery源码学习javascript(三)
Dec 27 Javascript
Jquery Ajax方法传值到action的方法
May 11 Javascript
JavaScript中连接操作Oracle数据库实例
Apr 02 Javascript
jquery实现表单验证并阻止非法提交
Jul 09 Javascript
jQuery实现Tab选项卡切换效果简单演示
Nov 23 Javascript
理解javascript定时器中的单线程
Feb 23 Javascript
Node.js的项目构建工具Grunt的安装与配置教程
May 12 Javascript
domReady的实现案例
Nov 23 Javascript
jQuery UI仿淘宝搜索下拉列表功能
Jan 10 Javascript
JavaScript设计模式之策略模式实现原理详解
May 29 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
javascript动态添加表格数据行(ASP后台数据库保存例子)
2010/05/08 Javascript
关于window.pageYOffset和document.documentElement.scrollTop
2011/04/05 Javascript
JavaScript高级程序设计阅读笔记(十六) javascript检测浏览器和操作系统-detect.js
2012/08/14 Javascript
js控制的遮罩层实例介绍
2013/05/29 Javascript
Jquery选择子控件"大于号"和" "区别介绍及使用示例
2013/06/25 Javascript
JS实现无限级网页折叠菜单(类似树形菜单)效果代码
2015/09/17 Javascript
5个最顶级jQuery图表类库插件【jquery插件库】
2016/05/05 Javascript
AngularJS实现星星等级评分功能
2016/09/24 Javascript
Javascript中常用的检测方法小结
2016/10/08 Javascript
JavaScript实现反转字符串的方法详解
2017/04/27 Javascript
JQuery Ajax动态加载Table数据的实例讲解
2018/08/09 jQuery
微信小程序获取用户openid的实现
2018/12/24 Javascript
nodejs搭建本地服务器并访问文件操作示例
2019/05/11 NodeJs
Node.js从字符串生成文件流的实现方法
2019/08/18 Javascript
微信小程序按顺序同步执行的两种方式
2019/12/20 Javascript
jQuery实现tab栏切换效果
2020/12/22 jQuery
git使用.gitignore设置不生效或不起作用问题的解决方法
2017/06/01 Python
Python模块结构与布局操作方法实例分析
2017/07/24 Python
浅谈Python处理PDF的方法
2017/11/10 Python
解决每次打开pycharm直接进入项目的问题
2018/10/28 Python
详解如何在cmd命令窗口中搭建简单的python开发环境
2019/08/29 Python
PyCharm上安装Package的实现(以pandas为例)
2020/09/18 Python
python3爬虫中多线程进行解锁操作实例
2020/11/25 Python
美国诺德斯特龙百货官网:Nordstrom
2016/08/23 全球购物
英语自荐信常用语句
2013/12/13 职场文书
酒店销售经理岗位职责
2014/01/31 职场文书
会计专业毕业生求职信
2014/07/04 职场文书
中学生爱国演讲稿
2014/09/05 职场文书
刑事代理授权委托书
2014/09/17 职场文书
乡镇领导班子四风对照检查材料
2014/09/27 职场文书
旷课检讨书范文
2014/10/30 职场文书
新教师个人工作总结
2015/02/06 职场文书
简述python四种分词工具,盘点哪个更好用?
2021/04/13 Python
利用Python判断整数是否是回文数的3种方法总结
2021/07/07 Python
Go中的条件语句Switch示例详解
2021/08/23 Golang
JDK8中String的intern()方法实例详细解读
2022/09/23 Java/Android