深入理解JavaScript系列(45):代码复用模式(避免篇)详解


Posted in Javascript onMarch 04, 2015

介绍

任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量避免使用这些模式,因为或多或少有带来一些问题;第二排是推荐篇,指的是推荐大家使用的模式,一般不会有什么问题。

模式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); // function

console.log(kid.say()); // Patrick

console.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); // undefined

console.log(typeof kid.say); // function

kid.name = 'Patrick';

console.log(kid.say()); // Patrick

console.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;

        C.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); // undefined

console.log(typeof kid.say); // function

kid.name = 'Patrick';

console.log(kid.say()); // Patrick

var kid2 = new Child("Tom");

console.log(kid.say()); 

console.log(kid.constructor.name); // Child

console.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.

    // 继承

    Parent = Parent || Object;

    F = function () {

    };

    F.prototype = Parent.prototype;

    Child.prototype = new F();

    Child.uber = Parent.prototype;

    Child.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); // true

console.log(clark instanceof SuperMan); // true

怎么样?看着是不是有点晕,说好点,该模式的语法和规范拧得和别的语言一样,你愿意用么?咳。。。

总结

以上六个模式虽然在某种特殊情况下实现了某些功能,但是都存在各自的缺点,所以一般情况,大家要避免使用。

Javascript 相关文章推荐
用JS判断IE版本的代码 超管用!
Aug 09 Javascript
JSONP获取Twitter和Facebook文章数的具体步骤
Feb 24 Javascript
原生js实现模拟滚动条
Jun 15 Javascript
js实现仿MSN带关闭功能的右下角弹窗代码
Sep 04 Javascript
通过node-mysql搭建Windows+Node.js+MySQL环境的教程
Mar 01 Javascript
HTML页面,测试JS对C函数的调用简单实例
Aug 09 Javascript
第一次接触神奇的Bootstrap导航条
Aug 09 Javascript
jquery 中toggle的2种用法详解(推荐)
Sep 02 Javascript
js实现可旋转的立方体模型
Oct 16 Javascript
canvas滤镜效果实现代码
Feb 06 Javascript
JavaScript设计模式之代理模式简单实例教程
Jul 03 Javascript
VUE解决跨域问题Access to XMLHttpRequest at
May 06 Vue.js
深入理解JavaScript系列(44):设计模式之桥接模式详解
Mar 04 #Javascript
JS实现FLASH幻灯片图片切换效果的方法
Mar 04 #Javascript
javascript下拉框选项单击事件的例子分享
Mar 04 #Javascript
js实现仿QQ秀换装效果的方法
Mar 04 #Javascript
深入理解JavaScript系列(43):设计模式之状态模式详解
Mar 04 #Javascript
深入理解JavaScript系列(42):设计模式之原型模式详解
Mar 04 #Javascript
javascript 动态创建表格的2种方法总结
Mar 04 #Javascript
You might like
使用adodb lite解决问题
2006/12/31 PHP
Zend Framework教程之Bootstrap类用法概述
2016/03/14 PHP
javascript 全等号运算符使用说明
2010/05/31 Javascript
解析URI与URL之间的区别与联系
2013/11/22 Javascript
javascript 实现子父窗体互相传值的简单实例
2014/02/17 Javascript
基于javascript实现的搜索时自动提示功能
2014/12/26 Javascript
jQuery中:input选择器用法实例
2015/01/03 Javascript
JS实现表单中checkbox对勾选中增加边框显示效果
2015/08/21 Javascript
JS动态添加选项案例分析
2016/10/17 Javascript
用vue和node写的简易购物车实现
2017/04/25 Javascript
Array数组对象中的forEach、map、filter及reduce详析
2018/08/02 Javascript
jQuery实现左右两个列表框的内容相互移动功能示例
2019/01/27 jQuery
IE11下处理Promise及Vue的单项数据流问题
2019/07/24 Javascript
微信小程序引入模块中wxml、wxss、js的方法示例
2019/08/09 Javascript
python动态加载变量示例分享
2014/02/17 Python
按日期打印Python的Tornado框架中的日志的方法
2015/05/02 Python
深入解析Python的Tornado框架中内置的模板引擎
2016/07/11 Python
Python实现螺旋矩阵的填充算法示例
2017/12/28 Python
Python将json文件写入ES数据库的方法
2019/04/10 Python
django框架CSRF防护原理与用法分析
2019/07/22 Python
django将数组传递给前台模板的方法
2019/08/06 Python
Python PyInstaller库基本使用方法分析
2019/12/12 Python
keras 权重保存和权重载入方式
2020/05/21 Python
Keras框架中的epoch、bacth、batch size、iteration使用介绍
2020/06/10 Python
css3圆角样式分享自定义按钮样式
2013/12/27 HTML / CSS
工程造价专业大学生自荐信
2013/10/01 职场文书
应届毕业生求职信范文分享
2013/12/26 职场文书
酒店总经理欢迎词
2014/01/08 职场文书
护理专业毕业生自荐书
2014/05/24 职场文书
团日活动总结怎么写
2014/06/25 职场文书
2014党员自我评议表范文
2014/09/20 职场文书
党的群众路线教育实践活动个人对照检查材料(教师)
2014/11/04 职场文书
2015年计划生育责任书
2015/05/08 职场文书
金正昆讲礼仪观后感
2015/06/11 职场文书
2016年教师师德师风承诺书
2016/03/25 职场文书
MySQL的prepare使用以及遇到的bug
2022/05/11 MySQL