`
aidxn527
  • 浏览: 43374 次
  • 性别: Icon_minigender_1
  • 来自: 苏州
社区版块
存档分类

Javascript乱弹设计模式系列(0) - 面向对象基础以及接口和继承类的实现

    博客分类:
  • JS
阅读更多

理论知识

1. 首先Javascript是弱类型语言,它定义变量时不必声明类型,如var Person = new Person(),它的变量类型为“var”,现在的C# 3.0也引进了这种匿名类型的概念,弱类型的变量产生了极大的灵活性,因为Javascript会根据需要来进行类型转换。所以这也决定了它采用了晚绑定的方法,即在运行后才知道变量的类型;

2. 面向对象概念不必多说,封装,继承,多态;

3. Javascript对象的类型主要分为三种:本地对象,如String,Array,Date等;内置对象,如Global,Math等;宿主对象,是指BOM,DOM对象等等;变量范围包括传统面向对象程序设计中的作用域,如公有,保护,私有,静态等等;

 

主要内容

1. 现在让我们来看看Javascript怎样创建对象的:

function Man() {
   //  
}
Man.prototype.getNickName = function() {
    return "Leepy";
}; 

var man = new Man();
var name = man.getNickName(); 

 这样就创建了最简单的类和对象,其中我们可以把function Man() {} 看作是Man类的构造函数,getNickName()看作是Man类的方法,准确说可以“当作”是Man类的公共方法;为什么要说是当作呢?那是因为其实Javascript实际上并没有一个私有共有的划分,因此开发者们自己指定了这样的规约,那么规约是什么样的呢?我这里把Man类的清单完整地列出来:

 

function Man() {
    // 私有静态属性
    var Sex = "男";
    //私有静态方法
    function checkSex() {
        return (Sex == "男");
    }
    //私有方法
    this._getSex = function() {
        //调用私有静态方法
        if(checkSex())
            return "男";
        else
            return "女";
    }
    //私有方法
    this.getFirstName = function() { 
        return "Li";
    };
    //私有方法
    this.getLastName = function() {
        return "Ping";
    };
}
//公共方法
Man.prototype.getNickName = function() {
    return "Leepy";
};
//公共方法
Man.prototype.getFullName = function() {
    return this.getFirstName() + " " + this.getLastName();
};
//公共方法
Man.prototype.getSex = function() {
    //调用私有方法
    return this._getSex();
};
//公共静态方法
Man.say = function() {
    return "Happy new year!";
}

 

这样的类是否看起来和传统的类很相似了呢

 

2. 接下来这个是本篇的一个重点,就是用Javascript如何设计一个接口,然后让类继承于它。

首先,先让我们看传统的C#语言是如何设计接口的吧:

public interface Person
{
    string GetName();
    void SetName(string name);
}
public class Man : Person
{
    private string _name; 

    public string GetName()
    {
        return _name;
    }
    public void SetName(string name)
    {
        _name = name;
    }
} 

 

接口中可以声明属性、方法、事件和类型(Structure),(但不能声明变量),但是并不能设置这些成员的具体值,也就是说,只能定义,不能给它里面定义的东西赋值,而接口作为它的继承类或者派生类的规约,继承类或者它的派生类能够共同完成接口属性、方法、事件和类型的具体实现,因为这里GetName(),SetName(),不管是方法名还是属性调用顺序上都是要保持一致的;

 

那么有了这样的一个基于接口的思想,我们设计Javascript的接口类的时候也需要考虑到这个规范。我先从主JS文件调用端开始说起:

 

var Person = new Interface("Person", [["getName", 0], ["setName", 1]]); 

 

其中Interface类是稍后要说的接口类,第一个参数"Person"是接口类的名称,第二个参数是个二维数组,"getName"是接口方法的名称,"0"是该方法所带的参数个数(因为Javascript是弱语言,所以类型是不确定的,所以只要记住参数个数就好,"0"可以省略不写),"setName"同理。这样一个接口定义好了。怎样使用它呢?

function Man() 
{
    this.name = "";
    Interface.registerImplements(this, Person);
}
Man.prototype.getName = function() {
    return this.name;
};
Man.prototype.setName = function(name) {
    this.name = name;
}; 

 

看到Man的构造函数里面包含

Interface.registerImplements(this, Person);

它是用来将实例化的this对象继承于Person接口,然后继承类对接口的方法进行实现。

代码看起来是不是很清晰和简单呢^_^,那么现在要开始介绍真正的核心代码Interface.js了:

先看Interface的构造函数部分

function Interface(name, methods) 
{
    if(arguments.length != 2) {
        throw new Error("接口构造函数含" + arguments.length + "个参数, 但需要2个参数.");
    }
    this.name = name;
    this.methods = [];
    if(methods.length < 1) {
        throw new Error("第二个参数为空数组.");
    }
    for(var i = 0, len = methods.length; i < len; i++) {
        if(typeof methods[i][0] !== 'string') {
            throw new Error("接口构造函数第一个参数必须为字符串类型.");
        }
        if(methods[i][1] && typeof methods[i][1] !== 'number') {
            throw new Error("接口构造函数第二个参数必须为整数类型.");
        }
        if(methods[i].length == 1) {
            methods[i][1] = 0;
        } 

        this.methods.push(methods[i]);
    }    
};

 

 

刚才看到了var Person = new Interface("Person", [["getName", 0], ["setName", 1]]);,这里将两个参数分别保存起来;

调用方法部分

Interface.registerImplements = function(object) { 

    if(arguments.length < 2) {
        throw new Error("接口的实现必须包含至少2个参数.");
    } 

    for(var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error("从第2个以上的参数必须为接口实例.");
        }
        for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
            var method = interface.methods[j][0];
            if(!object[method] || typeof object[method] !== 'function' || object[method].getParameters().length != interface.methods[j][1]) {
                throw new Error("接口的实现对象不能执行" + interface.name + "的接口方法" + method + ",因为它找不到或者不匹配.");
            }
        }
    }
}; 

 

刚才这句Interface.registerImplements(this, Person);,实际上这里是把this对象的方法名以及参数个数与刚Person保存的methods逐一进行比较,如果找不到或者不匹配,就警告错误;其中object[method].getParameters().length,调用了如下的代码:

 

Function.prototype.getParameters = function() { 

    var str = this.toString();
    var paramString = str.slice(str.indexOf('(') + 1, str.indexOf(')')).replace(/\s*/g,'');     //取得参数字符串
    try
    {
        return (paramString.length == 0 ? [] : paramString.split(','));
    }
    catch(err)
    {
        throw new Error("函数不合法!");
    }
} 

 

 

 getParrameters()方法作为Function对象的一个扩展,功能是取得方法含有的参数数组;

Interface.js完整的代码如下:

 

Interface.js文件
function Interface(name, methods) 
{
    if(arguments.length != 2) {
        throw new Error("接口构造函数含" + arguments.length + "个参数, 但需要2个参数.");
    }
    this.name = name;
    this.methods = [];
    if(methods.length < 1) {
        throw new Error("第二个参数为空数组.");
    }
    for(var i = 0, len = methods.length; i < len; i++) {
        if(typeof methods[i][0] !== 'string') {
            throw new Error("接口构造函数第一个参数必须为字符串类型.");
        }
        if(methods[i][1] && typeof methods[i][1] !== 'number') {
            throw new Error("接口构造函数第二个参数必须为整数类型.");
        }
        if(methods[i].length == 1) {
            methods[i][1] = 0;
        } 

        this.methods.push(methods[i]);
    }    
}; 

Interface.registerImplements = function(object) { 

    if(arguments.length < 2) {
        throw new Error("接口的实现必须包含至少2个参数.");
    } 

    for(var i = 1, len = arguments.length; i < len; i++) {
        var interface = arguments[i];
        if(interface.constructor !== Interface) {
            throw new Error("从第2个以上的参数必须为接口实例.");
        }
        for(var j = 0, methodsLen = interface.methods.length; j < methodsLen; j++) {
            var method = interface.methods[j][0];
            if(!object[method] || typeof object[method] !== 'function' || object[method].getParameters().length != interface.methods[j][1]) {
                throw new Error("接口的实现对象不能执行" + interface.name + "的接口方法" + method + ",因为它找不到或者不匹配.");
            }
        }
    }
}; 

Function.prototype.getParameters = function() { 

    var str = this.toString();
    var paramString = str.slice(str.indexOf('(') + 1, str.indexOf(')')).replace(/\s*/g,'');     //取得参数字符串
    try
    {
        return (paramString.length == 0 ? [] : paramString.split(','));
    }
    catch(err)
    {
        throw new Error("函数不合法!");
    }
} 

 

 

好了该创建一个html页面来试试效果了:

 

<script type="text/javascript">
function test()
{
    var man = new Man();
    man.setName("Leepy");
    alert(man.getName());
}
</script> 

<input type="button" value="click" onclick="test();" />

 

 

最终结果为:"Leepy"的弹出框;

这里还有一点要强调,如果接口上的方法没有在继承类上得到完全实现,或者方法参数个数不匹配,那么就会提示错误;

3. 如果我要一个类继承于另一个类该怎么做呢,继续看例子,这里我再定义一个SchoolBoy(男学生)类:

 

function SchoolBoy(classNo, post)
{
    Man.call(this);
    this._chassNo = classNo;
    this._post = post;
}
SchoolBoy.prototype = new Man();
SchoolBoy.prototype.getName = function() {
    return "Mr " + this.name;
}
SchoolBoy.prototype.setName = function(name) {
    this.name = name + "'s";
}

 

 

其中Man.call(this);实际上是将Man中的关键字this赋值于SchoolBoy对象中去,那么SchoolBoy就拥有了Man构造函数中的name属性了;

SchoolBoy.prototype = new Man();实际上是把Man的prototype赋值给SchoolBoy.prototype,那么SchoolBoy就有了Man类中的方法;

而后面跟着的getName(),setName(),实际上是覆盖了前面继承于Man类中的方法了;

然后看看效果:

var schoolboy = new SchoolBoy("三年二班", "班长");
schoolboy.setName("周杰伦");
alert(schoolboy.getName());
<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />-->

最后结果为:"Mr 周杰伦's"的弹出框;

总结

该篇文章主要讲述一些Javascript面向对象的基础以及接口和继承类的实现等等;下一篇将开始真正的Javascript设计模式征程,并且我会结合一些网站系统上的实例来讲;

 

 

本文来自:http://www.cnblogs.com/liping13599168/archive/2009/01/03/1367334.html

分享到:
评论

相关推荐

    对话框乱弹的小程序源码

    它将Windows API封装成易于理解和使用的对象,让开发者能更高效地构建Windows桌面应用程序,包括各种窗口、对话框、控件等。 在这个小程序中,"对话框"(Dialog)是MFC中的一种关键元素,它代表了Windows上的一个...

    《浅析新媒介生态环境下广播娱乐节目的编辑特征——以FM101.1西安乱弹“刘翔来了”为例》-论文.zip

    这篇论文《浅析新媒介生态环境下广播娱乐节目的编辑特征——以FM101.1西安乱弹“刘翔来了”为例》深入探讨了在新媒体环境下,广播娱乐节目如何适应和利用新媒介特性,实现自身内容创新与传播效果的提升。通过对FM101...

    Python-使用fiddler工具进行抓包使用python进行osc乱弹抢沙发

    使用fiddler工具进行抓包,使用python进行osc乱弹抢沙发

    乱弹爱丽丝钢琴曲谱双手数字简谱.pdf

    《乱弹爱丽丝》是一首深受广大音乐爱好者喜爱的钢琴曲,它的简谱版本为演奏者提供了方便,使得无论是初学者还是有一定基础的琴友都能尝试演奏这首曲子。在简谱中,数字代表音高,不同位置的数字对应钢琴键盘上的不同...

    into沙龙第期康国庆乱弹传统企业转型以及与互联网结合的方式PPT教案.pptx

    互联网可以帮助打破这些壁垒,如通过渠道信息化提升流通效率,利用电商平台拓宽销售渠道,探索工业4.0以实现智能制造,通过O2O模式升级服务业,以及借助互联网传播力量推动文化产业创新。 【互联网的角色】 在传统...

    免费教程大型网站整理.docx

    这篇文档主要列举了一系列提供免费教程的大型网站,涵盖了广泛的IT技术领域,包括但不限于操作系统、网站设计、多媒体处理、软件应用、编程语言、网络安全以及考试认证等。这些网站旨在帮助用户提升技能,学习新知识...

    《浅析新媒介生态环境下广播娱乐节目的编辑特征——以FM101.1西安乱弹“刘翔来了”为例》.doc

    广播节目在传统媒介环境下通常采用“采编播”的模式,而在新媒介环境中,为了适应更广阔受众的需求和产业化发展,广播节目,特别是娱乐类节目,开始注重“创编演”的创新过程。 广播娱乐节目编辑的核心在于创造...

    利用GestureDetector实现页面滑动Demo

    在`onScroll`或`onFling`中,你可以根据滑动的方向和距离来决定页面是否需要滑动以及滑动的距离。 3. 处理触摸事件: 在你的Activity或Fragment中,你需要覆盖`onTouchEvent(MotionEvent event)`方法,并在其中...

    动软代码生成器 修复单类代码生成器4个问题。

    修复单类代码生成器4个问题。 2.新增创建加载数据库时,表名过滤功能。 3.表名生成命名规则,字符串替换功能。 4.模板中字段排序方法公开。 5.字段默认值函数的处理。 6.导出的sql脚本中,单引号 '的问题。 7.工具-...

    Ajax使用杂谈 也许也是乱弹

    在早期,Ajax的实现依赖于iframe和JavaScript的top.Function调用来实现远程脚本加载,这种方法虽然简单,但在后期维护和跨域处理上存在诸多困难。XMLHttpRequest对象的诞生,让Ajax的开发变得更加简洁,但各浏览器...

    ViewPager+RadioGroup实现微信UI界面

    在这个类中,我们需要重写`getCount()`方法来确定页面数量,以及`instantiateItem()`和`destroyItem()`方法来添加和移除页面。 3. **设置ViewPager**:在Activity中,实例化`ViewPager`,并用刚才创建的`...

    Z-Blog博客系统 2.2 Prism Build 130801

    乱弹随机跳转到博客的任意一篇文章。TotoroⅢ,基于TotoroII的Z-Blog的评论及引用管理审核系统增强版。 8月1号发布,修正了0722版的一些问题,请大家更新! 主要更新 [主要更新]后台语言包切换 [主要更新]WAP插件...

    Android快速索引:实现微信通讯录效果

    在`QuickActionBar`这个文件中,可能包含了实现快速索引的自定义View类,你可以查看其源代码来学习如何处理触摸事件和改变视图状态。通过深入理解这些知识点,你就能实现一个与微信通讯录类似的快速索引功能。在实际...

    四川省泸州市龙马潭区公共基础知识历年真题汇总.doc

    8. 乱弹戏曲:乱弹是河北的传统戏曲艺术形式,历史悠久,是当地人民的文化遗产,也是中国戏曲的重要组成部分。 以上知识点涵盖了金融交易、行政职务、合同法、职业道德、公务员制度、信用消费、个人隐私权以及传统...

    Python-3.6.0.tar.gz

    - **新类型提示**:Python 3.5引入了类型注解,3.6进一步完善了类型检查系统,支持更多的内置类型和类类型注解。 2. **性能提升:** - **字典改进**:Python 3.6对字典的实现进行了优化,使其在插入和查找操作上...

    自己实现的QQ测运气小app

    【QQ测运气小app】是一款基于聚合数据接口开发的轻量级应用,旨在为用户提供趣味性的QQ运气测试体验。这款应用充分利用了ViewPager组件来实现平滑的页面切换效果,为用户带来流畅的操作体验。对于想要学习Android...

    免费教程大型网站整理(doc 19页).docx

    此外,像织梦乱弹和理想帝国这类网站提供了DW、FW、PS、FL等工具的插件、滤镜、字体、样式以及JS、ASP、PHP、DHTML等技术的教程和资源。 【综合学习平台与资源分享】 一些综合性的学习平台,如3D壁纸和模型下载...

    《浅析新媒介生态环境下广播娱乐节目的编辑特征——以FM101.1西安乱弹“刘翔来了”为例》.zip

    《浅析新媒介生态环境下广播娱乐节目的编辑特征——以FM101.1西安乱弹“刘翔来了”为例》.zip

Global site tag (gtag.js) - Google Analytics