js设计模式基础——继承

作者:bibodeng 发布于:2013-12-4 23:59 Wednesday 分类:web开发

js设计模式基础——继承

by bibodeng 2013-12-04

js中的继承

js中的继承分为几种:

  • 类式继承 (构造函数的prototype链扩展) extend
  • 原型式继承 (从对象的角度) clone
  • 掺元类 (混合多个类)

类式继承

使用原型链的方式,让构造函数的原型指向另外一个对象(注意是对象)。我们平常做的比较多的,就是创建一个新类,然用用prototype扩展这个类,然后生成的类的对象实例则具备了原型链对象中的方法和属性了。

让一个类继承另外一个类的四部曲:

  • 设置原型对象
  • 恢复构造函数
  • 执行构造函数(构造函数也执行父类构造函数)
  • 生成新对象

然而在new的过程中,将会调用自身的构造函数,让一个类继承另外一个类,就需要它调用一次父类的构造函数,从而在this中声明各种属性。并且把构造函数设置回自己的构造函数(因为会覆盖掉)。现在为了实现两个类之间的继承,实现一个模拟继承:

function extend(subClass, superClass){
    var F = function() {};
    F.prototype = superClass.prototype; // 这句挺巧妙
    subClass.prototype = new F();   // 相当于调用过了superClass的构造函数,并且将F的对象实例赋给了subClass的prototype对象
    subClass.prototype.constructor = subClass; // 恢复构造函数
}

原型式继承

从原有对象的基础上进行修改变换。类的基础是一个对象:

var Person = {
    name: 'ren',
    talk: function(){
        console.log("hi, my name is "+this.name);
    }
}

// 克隆方法,将obj放到新对象的原型链中
function clone(obj){
    function F(){};
    F.prototype = obj;
    return new F;
}

// 原型继承
newObj = clone(Person);

在clone之后,对于从原型继承而来的属性,直接更改的话会改变原型对象中的数据,会对别的子类产生影响,而如果给一个属性赋值的方式,如obj.name = "bibo" 将会新建一个新对象自己的属性。所以,要改变某个属性之前,先为它创建新的副本,而不是让它默认使用原型的值,这也能够解决上面所谓的读写不对称 ,这多少和我们之前的继承认识有所不同。不过可以使用hasOwnProperty来区分是实际成员还是继承的成员,因为hasOwnProperty是不把原型链中的属性或方法算在内的。

多类继承(混合两个类)

使用的是将一个类中的属性拷贝到另外一个类中。这样就把两个类(一个函数)的属性给混在一起了。

function mix(receivingClass, givingClass){
    if(arguments[2])
    {
        // 可能不止一个类掺入,存起所有prototype
        for(var i=0, len = arguments.length; i < len; i++){
            receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]];
        }
    }
    else
    {
        for(methodName in givingClass.prototype){
            if(!receivingClass.prototype[methodName]){
                receivingClass.prototype[methodName] = givingClass.prototype[methodName];
            }
        }
    }
}

上面的函数用于掺杂多个类的prototype属性。一般是继承prototype对象里面的东西:

var ClassA = function(){};
ClassA.prototype = {
    // 这里的才是prototype对象中的属性和方法
    method1: function(){console.log("method 1 call")}
}

// 假设有另外一个类:

var ClassB = function(){};

mix(ClassB, ClassA); // 将method1给混到ClassB中去

大部分代码都是从书中摘抄的,这里只是稍微梳理一下各种代码。其实最根本的还是弄清原型链的关系。对于问题的敏锐性,是能够注意到事物之间的关联,理清关键联系,这样能够朝着目标解决问题。


end

阅读全文>>

标签: web js 继承

评论(0) 引用(2) 浏览(2006)

简析js设计模式接口基础

作者:bibodeng 发布于:2013-12-2 19:56 Monday 分类:web开发

简析js设计模式接口基础

by bibodeng 2013-12-02

想起要对js设计模式中一些基础的代码做一个简单分析,让自己印象更加深刻。例如接口,继承,闭包等等,方便以后要的时候直接拿来。

接口

接口,学过Java的同学肯定知道,声明一个接口,里面有若干方法,而一个类负责实现(implements)它,语言本身的机制会强制该类必须实现接口中声明的所有方法,否则就会报错。实现接口的目的是为了提供一组通用的叫法,让不同的对象实现它。很常见的就是在组合模式中,父元素和子元素都实现了相同的接口,从而可以很直接地将请求从任意一层传递下去。总之,接口能够提供一个通用的方法库,也要保证各类都有实现所有方法。接口在js中的实现方法有三种:

  • 注释法 (就是用注释来说明)
  • 属性检查法
  • duck type(会呱呱叫的都是鸭子)

属性检查法

注释法就不详细看了,因为它就是用注释声明一些接口,而不做任何检查,完全靠人工检查是否实现了相应的方法。而属性检查法,相对来讲严格一点,它将一组接口的名字都放入一个数组中。

// 这是后面组合模式表单的一个例子
var ClassA = function(){
    // 声称自己有一组接口
    this.interfaces = ['Composite', 'FormItem'];
}

为了检查是否实现了相应的接口,就检查该类的实例是否具有某个接口,这个某个接口是作为字符串传入需要检查的接口名。

// 模仿implements
function implements(obj){
    // 对传入的参数(接口名进行检查)
    for (var i=1; i < arguments.length; i++)
    {
        var interfaceName = arguments[i];
        var interfaceFound = false;
        // 检查声称的接口 比对两个数组需要两个循环
        for (var j=0; j<obj.interfaces.length; j++){
            if (obj.interfaces[j] == interfaceName){
                interfaceFound = true;  // 接口j找到了
                break;
            }
        }
        // 只要有一个接口没有实现
        if(!interfaceFound){
            throw {
                name: 'interface error',
                msg: 'some interfaces not found in obj'
            }
            return false;
        }
    }
    return true;    // 全部通过检查
}

// 调用方法
if (!implements(obj, 'Composite', 'FormItem')){
    ...
}

这次只是把这些接口名都放到一个数组中,但是还是没有确保在ClassA中实现接口中的方法(还是以注释的方式说明)。在实践中看起来也没啥用处。我们需要的是真正能够检查对象的方法,我们瞬间想到了for (var index in obj) 对每个方法进行检查。而我们的接口,也应该放在一个像这样的对象中,它能够维护接口的名字和各种方法名。

{
    interfaceName: 'Composite',
    methods: ['add', 'remove', 'getChild']
}

初步的思想是有了,但是实现要灵活,能够生成一个如上的对象。duck typing就是这样做的:

鸭式辨形

会呱呱叫的两只脚走路的会游泳的就是鸭子。我们生活中常常是一个经验主义者,通过这样的方法来判断事物。所有,理解起来也不是很难:

// 接口对象
var Composite = new Interface('Composite', ['add', 'remove', 'getChild']);

// 要得到上面的对象,我们写一个构造函数专门用来新建接口对象
function Interface(interfaceName, methods){
    this.interfaceName = interfaceName;
    this.methods = methods;
    // new操作将返回this
}

// 如果要严密一点,就需要检查参数的个数和类型

这次就不用注释了,而且代码很明了。声明了一个接口对象Composite,它的名字叫做Composite,具有addremovegetChild三个方法。那么如何声明实现了该接口,并且用什么来确保对象实现了我们接口声明的方法呢?

这次都不用声明实现了该接口,只要实现了相应的方法就是实现了该接口。所以不用显式地声明implements了什么。而是在某个方法之前用ensureImplements来检查。至于设计成Interface的内置方法,还是普通函数,都是可以的。

// obj, interf1, interf2
Interface.ensureImplements = function(obj){
    if (arguments.length < 2){
        throw new Error("arguments require for at least 2");
    }

    // 依次检查 这次的参数是interface实例,不再是字符串
    // 而一个字符串数组也变成了真正的对象的属性
    for (var i=1; i<arguments.length; i++){
        var interface = arguments[i];
        // 严格的类型检查
        if (interface.constructor !== Interface){
            throw new Error("argument " + i + " is not the instance of Interface Class");
        }

        for (var j=0; j<interface.methods.length; j++){
            var method = interface.methods[j];
            if (!obj[method] || typeof obj[method] !== 'function'){
                throw new Error("ensureImplements error: method" + interface.methods[j] +
                    ' in interface '+ interface.interfaceName + ' was not found.');
            }
        }
    }
}

// 调用示例
function foo(formObj){
    // 不满足条件回报错
    Interface.ensureImplements(formObj, Composite, FormItem);

    // 使用接口中的方法
    formObj.remove();
    ...
}

主要就是实现一个Interface类,供生成实例,也提供一个ensureImplement方法。只要引入了这个类,就可以使用new一个Interface,然后检查的方式严格要求类实现了接口中的方法。但是我总觉得少了一步,就是声明一下某个类实现了某个接口。当然也可以用数组将所实现的接口都存一个对应的应用,如{'Composite': Composite}。但是这样看起来就不像是鸭式辨型了。


end

阅读全文>>

标签: web js 接口 interface

评论(0) 引用(2) 浏览(2114)

[书]读《js设计模式》

作者:bibodeng 发布于:2013-11-29 11:17 Friday 分类:web开发

读《js设计模式》

by bibodeng 2013-11-29

迫切的需求

接触前端大概一年了,由于许多深入的东西都不懂,所以做不出高级的东西。对于稍微复杂一点的需求,都觉得难以下手。于是意识到了要学学设计模式了,所以就翻开(准确来说是点开了)这本《javascript设计模式》。由于有了js的基础,在读了《js编程精粹》之后,对于这门语言有了喜爱和习惯,于是这...

阅读全文>>

标签: web js 继承 笔记 设计模式

评论(0) 引用(1) 浏览(1947)

[书]人生是一场修行——读《少有人走的路》

作者:bibodeng 发布于:2013-11-28 21:20 Thursday 分类:读书笔记

人生是一场修行——读《少有人走的路》

by bibodeng 2013-11-28

对自己负责

也许这种文字不太适合放到博客里面去,因为未必有人感兴趣。花几天看完了《少有人走的路》,也许该写写读后感,因为我对于书中的内容有共鸣。都说读书是从书中的世界里面发现自己,从这本书里面我看到了自己的影子。常人掌握控制意识的能力能够做出更加恰当的决策,而探索未知的潜意识更多是...

阅读全文>>

标签: 心理学 心智 成熟

评论(0) 引用(0) 浏览(1741)

重写share2SNS

作者:bibodeng 发布于:2013-11-21 10:48 Thursday 分类:web开发

重写share2SNS

by bibodeng 2013-11-20

前言

前段时间,@myunlessor 兄跟我讨论的时候提到我之前用的那个分享到SNS网站的js写得并不够优雅,有许多冗余的地方。而我最近也在看javascript的设计模式,发现代理模式非常适合这种用来发送一组GET请求的情况,尤其是参数较少的时候。于是我就试着实现一个代理模式实现的版本。 ...

阅读全文>>

标签: javascript 重构 设计模式

评论(0) 引用(2) 浏览(1781)

[转]精力的培养

作者:bibodeng 发布于:2013-11-12 11:22 Tuesday 分类:生活点滴

精力的培养

   人的精力是颇为有限的。付出的过程比获取要长很多。做任何有益于自己的,成长性的事情都需要付出精力,这也要求人们有节制的使用这一无形资本——我认为这些显而易见的道理,越早想明白越好。
   曾经有很长的一段时间我不明白为什么每当我参加一些人数众多,气氛热闹,互动频繁的活动时就会情绪低落,即使是参加大型同学聚会,面对大家欢快的讨论,我也多少有些拘谨。直...<p class="readmore"><a href="http://www.bibodeng.com/?post=142">阅读全文&gt;&gt;</a></p>

标签: 习惯 精力 爱好

评论(0) 引用(4) 浏览(1623)

latex生成各种格式电子书

作者:bibodeng 发布于:2013-11-9 23:36 Saturday 分类:资源工具

使用latex源码生成各种格式电子书

by bibodeng 2013-11-09

前言

为了让电子书能够在更多的平台上被阅读,那么则需要生成各种版本的电子书,这个过程真的有点蛋疼,但是通过各种非常有用的工具,干起来也非常快。下面主页记录一下常用的格式的生成:

PDF,mobi, epub, html

其中PDF是最容易的,latex编译默认就输出P...

阅读全文>>

标签: latex xelatex 电子书 排版 ubuntu 多屏幕

评论(0) 引用(1) 浏览(2643)

xelatex在文档处理中的使用

作者:bibodeng 发布于:2013-11-9 13:18 Saturday 分类:资源工具

xelatex在文档处理中的使用

by bibodeng 2013-11-09

latex和pdflatex的问题

使用latex来直接编译,在有\tableofcontent的情况下会出现一些怪异的unicode char \u8之这样的错误,使得目录不完整。其原因是使用的CJKutf8的宏包所包含的utf8字符是不完整的,故而有些中文字符支持不完整。...

阅读全文>>

标签: latex xelatex 电子书 排版 ubuntu 多屏幕

评论(0) 引用(0) 浏览(2395)

常用latex代码块

作者:bibodeng 发布于:2013-11-3 16:27 Sunday 分类:资源工具

常用latex代码块

by bibodeng 2013-11-3

为啥搞latex

其实接触latex也有些日子了,本来是一直打算用它来排版我们自己的简历,论文,还有我们业余写的电子书。最近和思愿在折腾这个东西,故而觉得有必要整理出一篇常用的latex代码块出来,然后结合我们的需要发挥。

宿舍一个哥们总是说我折腾,linux,latex,Qt,折腾的东西真的不少...

阅读全文>>

标签: latex 总结 代码

评论(0) 引用(0) 浏览(2921)

事件代理实现

作者:bibodeng 发布于:2013-11-3 11:26 Sunday 分类:web开发

事件代理实现

by bibodeng 2013-10-29

事件代理的原理

所谓事件代理,就是说让另外一个元素,一般是父元素来绑定事件,然后处理的是子元素被点击后的逻辑。这样的目的是减少绑定事件的消耗,因为往往一个父元素下有很多个相同的子元素,它们所绑定的事件也是一样的,故而可以将这个消耗给转移到同一个绑定中,既提升效率,也使得程序变得优雅。我在博客园找到一篇事件代理的[...

阅读全文>>

标签: javascript web 事件

评论(0) 引用(2) 浏览(1922)

Powered by emlog 京ICP备16017775