JavaScript代码复用模式详解

代码复用及其原则

代码复用,顾名思义就是对曾经编写过的代码的一部分甚至全部重新加以利用,从而构建新的程序。在谈及代码复用的时候,我们首先可以想到的是继承性。代码复用的原则是:

优先使用对象组合,而不是类继承

在js中,由于没有类的概念,因此实例的概念也就没多大意义,js中的对象是简单的键-值对,可以动态的创建和修改它们。

但在js中,我们可以使用构造函数和new操作符来实例化一个对象,这与其他使用类的编程语言在语法上有其相似之处。

例如:

var trigkit4 = new Person();

js在调用构造函数Person时似乎看起来是一个类,但其实际上仍然是一个函数,这让我们产生了一些假定在类的基础上的开发思路和继承模式,我们可以称之为“类式继承模式”。

传统的继承模式是需要class关键字的,我们假定以上的类式继承模式为现代继承模式,这是一种不需要以类的方式考虑的模式。

类式继承模式

看下面两个构造函数Parent()Child()的例子:

<script type="text/javascript">    function Parent(name){        this.name = name || 'Allen';    }    Parent.prototype.say = function(){        return this.name;    }    function Child(name){}    //用Parent构造函数创建一个对象,并将该对象赋值给Child原型以实现继承    function inherit(C,P){        C.prototype = new P();//原型属性应该指向一个对象,而不是函数    }    //调用声明的继承函数    inherit(Child,Parent);</script>

当使用new Child()语句创建一个对象时,它会通过原型从Parent()实例获取它的功能,比如:

var kid = new Child();
kid.say();
//Allen

原型链

讨论一下类式继承模式下原型链的工作原理,我们将对象看做是内存中某处的块,该内存块包含数据以及指向其他块的引用。当用new Parent()语句创建一个对象时,就会创建如下图左边的这样一个块,这个块保存了name属性,如果想访问say()方法,我们可以通过指向构造函数Parent()prototype(原型)属性的隐式链接__proto__,便可访问右边区块Parent.prototype

那么,当使用var kid = new Child()创建新对象时会发生什么?如下图:

使用new Child()语句所创建的对象除了隐式链接__proto__外,它几乎是空的。这种情况下,__proto__指向了在inherit()函数中使用new Parent()语句所创建的对象

当执行kid.say()时,由于最左下角的区块对象并没有say()方法,因此他将通过原型链查询中间的区块对象,然而,中间的区块对象也没有say()方法,因此他又顺着原型链查询到最右边的区块对象,而该对象正好有say()方法。完了吗?

执行到这里的时候并没有完,在say()方法中引用了this.name,this指向构造函数所创建的对象,在这里,它指向了new Child()这个区块,然而,new Child()中并没有name属性,为此,将查询中间区块,而中间区块正好有name属性,至此,原型链的查询完毕。

更详细的讨论请查看我这篇文章:javascript学习笔记(五)原型和原型链详解

共享原型

本模式的法则在于:可复用的成员应该转移到原型中而不是放置在this中。因此,处于继承的目的,任何值得继承的东西都应该放在原型中实现。所以,可以将子对象的原型与父对象的原型设置为相同即可,如下示例所示:

function inherit(C,P){    C.prototype = P.prototype;}

子对象和父对象共享同一个原型,并且可以同等的访问say()方法。然而,子对象并没有继承name属性

原型继承

原型继承是一种“现代”无类继承模式。看如下实例:

<script type="text/javascript">    //要继承的对象    var parent = {        name : "Jack"  //这里不能有分号哦    };
    //新对象    var child = Object(parent);
    alert(child.name);//Jack</script>

在原型模式中,并不需要使用对象字面量来创建父对象。如下代码所示,可以使用构造函数来创建父对象,这样做的话,自身的属性和构造函数的原型的属性都将被继承。

<script type="text/javascript">    //父构造函数    function Person(){        this.name = "trigkit4";    }    //添加到原型的属性    Person.prototype.getName = function(){        return this.name;    };    //创建一个新的Person类对象    var obj = new Person();    //继承    var kid = Object(obj);    alert(kid.getName());//trigkit4</script>

本模式中,可以选择仅继承现有构造函数的原型对象。对象继承自对象,而不论父对象是如何创建的,如下实例:

<script type="text/javascript">    //父构造函数    function Person(){        this.name = "trigkit4";    }    //添加到原型的属性    Person.prototype.getName = function(){        return this.name;    };    //创建一个新的Person类对象    var obj = new Person();    //继承    var kid = Object(Person.prototype);    console.log(typeof kid.getName);//function,因为它在原型中    console.log(typeof kid.name);//undefined,因为只有该原型是继承的</script>
(0)

相关推荐

  • 简单谈谈javascript代码复用模式

    代码复用有一个著名的原则,是GoF提出的:优先使用对象组合,而不是类继承.在javascript中,并没有类的概念,所以代码的复用,也并不局限于类式继承.javascript中创建对象的方法很多,有构造函数,可以使用new创建对象,并且可以动态的修改对象.javascript的非类式继承(可称为现代继承模式)复用方法也很多,例如,利用其它对象组合成所需要的对象,对象混入技术,借用和复用所需要的方法. 类式继承模式-默认模式 两个构造函数Parent和Child的例子: 复制代码 代码如下: fu

  • JavaScript代码复用模式实例分析

    任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量避免使用这些模式,因为或多或少有带来一些问题:第二排是推荐篇,指的是推荐大家使用的模式,一般不会有什么问题. 模式1:默认模式 代码复用大家常用的默认模式,往往是有问题的,该模式使用Parent()的构造函数创建一个对象,并且将该对象赋值给Child()的原型.我们看一下代码: 复制代码 代码如下: fu

  • JavaScript代码复用模式详解

    代码复用及其原则 代码复用,顾名思义就是对曾经编写过的代码的一部分甚至全部重新加以利用,从而构建新的程序.在谈及代码复用的时候,我们首先可以想到的是继承性.代码复用的原则是: 优先使用对象组合,而不是类继承 在js中,由于没有类的概念,因此实例的概念也就没多大意义,js中的对象是简单的键-值对,可以动态的创建和修改它们. 但在js中,我们可以使用构造函数和new操作符来实例化一个对象,这与其他使用类的编程语言在语法上有其相似之处. 例如: var trigkit4 = new Person();

  • php 5.4 全新的代码复用Trait详解

    从PHP的5.4.0版本开始,PHP提供了一种全新的代码复用的概念,那就是Trait.Trait其字面意思是"特性"."特点",我们可以理解为,使用Trait关键字,可以为PHP中的类添加新的特性. 熟悉面向对象的都知道,软件开发中常用的代码复用有继承和多态两种方式.在PHP中,只能实现单继承.而Trait则避免了这点.下面通过简单的额例子来进行对比说明. 1. 继承 VS 多态 VS Trait 现在有Publish.php和Answer.php这两个类.要在其中

  • 如何为你的JavaScript代码日志着色详解

    前言 在使用 JavaScript 开发项目,可借助 console.log 来打印日志,以便捷分析问题:但,当接触相对比较项目,纯黑色的日志输出,就会使得其作用大大削弱:虽然 info, wran.error 等方法会区别颜色输出,但各自皆有其职责,不便挪来加以滥用:此时,就需求扩展些方法,来为你的 JavaScript 代码日志着色,使得日志可以发挥更大的价值. 要实现这个功能,其实很简单:利用 console.log 字符串替代和格式设置功能即可:下面为其格式说明符的完整列表: 说明符 输

  • Javascript设计模式之装饰者模式详解篇

    一.前言: 装饰者模式(Decorator Pattern):在不改变原类和继承的情况下动态扩展对象功能,通过包装一个对象来实现一个新的具有原对象相同接口的新的对象. 装饰者模式的特点: 1. 在不改变原对象的原本结构的情况下进行功能添加. 2. 装饰对象和原对象具有相同的接口,可以使客户以与原对象相同的方式使用装饰对象. 3. 装饰对象中包含原对象的引用,即装饰对象是真正的原对象经过包装后的对象. 二.Javascript装饰者模式详解: 描述: 装饰者模式中,可以在运行时动态添加附加功能到对

  • 深入理解JavaScript系列(46):代码复用模式(推荐篇)详解

    介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: 复制代码 代码如下: function object(o) {     function F() {     } F.prototype = o;     return new F(); } // 要继承的父对象 var parent = {     name: "Papa" }; // 新对象 var child = object(p

  • JavaScript设计模式之职责链模式详解

    目录 职责链模式 1. 现实中的职责链模式 2. 实际开发中的职责链模式 3. 用职责链模式重构代码 4. 灵活可拆分的职责链节点 5. 异步的职责链 6. 职责链模式的优缺点 7. 用 AOP 实现职责链 8. 小结 职责链模式 职责链模式的定义是:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系,将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止. 职责链模式的名字非常形象,一系列可能会处理请求的对象被连接成一条链,请求在这些对象之间依次传递,直到遇

  • JavaScript设计模式之中介者模式详解

    目录 中介者模式 现实中的中介者 中介者模式的例子 泡泡堂游戏 为游戏增加队伍 玩家增多带来的困扰 用中介者模式改造泡泡堂游戏 小结 中介者模式 在我们生活的世界中,每个人每个物体之间都会产生一些错综复杂的联系.在应用程序里也是一样,程序由大大小小的单一对象组成,所有这些对象都按照某种关系和规则来通信. 平时我们大概能记住 10 个朋友的电话.30 家餐馆的位置.在程序里,也许一个对象会和其他 10 个对象打交道,所以它会保持 10 个对象的引用.当程序的规模增大,对象会越来越多,它们之间的关系

  • JavaScript 设计模式中的代理模式详解

    前言: 代理模式,代理(proxy)是一个对象,它可以用来控制对另一个对象的访问. 现在页面上有一个香港回归最想听的金典曲目列表: <ul id="container"> <li>我的中国心</li> <li>东方之珠</li> <li>香港别来无恙</li> <li>偏偏喜欢你</li> <li>相亲相爱</li> </ul> 需要给页面添加

随机推荐