前面说到,javascript的代码复用模式,可分为类式继承和非类式继承(现代继承)。这篇就继续类式继承。

类式继承模式-借用构造函数

使用借用构造函数的方法,可以从子构造函数得到父构造函数传任意数量的参数。这个模式借用了父构造函数,它传递子对象以绑定到this,并转发任意数量的参数:

  1. function Child(a,b,c,d){
  2. Parent.apply(this,arguments);
  3. }

在这种方式中,只能继承在父构造函数中添加到this的属性,并不能继承添加到原型中的成员。

使用借用函数构造模式的时候,子对象获得了继承成员的副本,这个与默认原型继承中的仅获取引用的方式是不同的。可以参考下面的例子:

  1. funciton Article(){
  2. this.tags = ['js','css'];
  3. }
  4. var article = new Article();
  5. function BlogPost(){
  6. }
  7. BlogPost.prototype = article;
  8. var blog = new BlogPost();
  9.  
  10. function StaticPage(){
  11. Article.call(this);
  12. }
  13. var page = new StaticPage();
  14.  
  15. console.log(article.hasOwnProperty('tags'));//true
  16. console.log(blog.hasOwnProperty('tags'));//false
  17. console,log(page.hasOwnProperty('tags'));//true

上面用两种方式继承了Article(),默认原型模式导致blog对象通过原型来获得他对tags属性的访问,所以blog对象没有将article作为自身的属性,所以当调用hasOwnProperty()时会返回false.而page对象本身具有一个tags属性,是因为他在调用父构造函数时,新对象会获得父对象中tags成员的副本,而不是引用。
可以通过下面的代码看到这个差异:

  1. blog.tags.push('html');
  2. page.tag.push('php');
  3. console.log(article.tags.join(','));//"js,css,html"

上面代码中,子对象blog修改了其tags属性,而这种方式也会修改父对象article,因为本质上blog.tags和article.tags指向了同一个数组,但修改page的tags不会影响父对象article,是由于在继承过程中page.tags是独立创建的一个副本。
关于原型链的工作流程:

  1. function Parent(name){
  2. this.name = name||"Adam";
  3. }
  4. Parent.prototype.say = {
  5. return this.name;
  6. };
  7. function Child(name){
  8. Parent.apply(this,arguments);
  9. }
  10. var kid = new Child("Patrick");
  11. console.log(kid.name);//"Patric"
  12. console.log(typeof kid.say);//undefined

上面代码里面没有使用Child.prototype,它只是指向一个空对象,借用父构造函数时,kid获得了自身属性name,没有继承过say()方法。继承是一次性完成的,仅会复制父对象的属性并将其作为自身的属性,所以也不会保留_proto_链接。

使用借用构造函数时,可以通过借用多个构造函数实现多重继承:

  1. function Cat(){
  2. this.legs = 4;
  3. this.say = function(){
  4. return "meaowww";
  5. };
  6. }
  7. function Bird(){
  8. this.wings = 2;
  9. this.fly = true;
  10. }
  11. function CatWings(){
  12. Cat.apply(this);
  13. Bird.apply(this);
  14. }
  15.  
  16. var jane = new CatWings();
  17. console.dir(jane);

运行结果:

  1. fly true
  2. legs 4
  3. wings 2
  4. say function()

借用构造函数的缺点,很明显,不能从原型中继承任何属性和方法,如上面Parent和Child的例子。对于父构造函数上使用this定义的方法也会创建多个副本。优点可以获得父对象自身成员的真实副本,不会存在子对象覆盖父对象的风险,可以传参数,可以多重继承。

类式继承模式-借用和设置原型

这个模式就是结合前面两种,先借用构造函数,也设置子构造函数的原型使其指向一个构造函数创建的实例。代码如下:

  1. function Child(a,b,c,d){
  2. Parent.apply(this,arguments);
  3. }
  4. Child.prototype = new Parent();

这样的优点,是代码运行后的结果对象能够获得父对象本身的成员副本以及指向父对象中可复用功能(以原型方式实现的功能),同时,子对象也可以将任意参数传递到父构造函数中,
这个是最接近Java或者C#的实现方式。可以继承父对象的一切,同时也可以安全的修改自身的属性,不会带来修改父对象的风险。

这样的缺点,是父构造函数被调用了两次,这会导致效率低下,自身的属性会被继承两次,如下面的name:

  1. function Parent(name){
  2. this.name = name||"Adam";
  3. }
  4. Parent.prototype.say = {
  5. return this.name;
  6. };
  7. function Child(name){
  8. Parent.apply(this,arguments);
  9. }
  10. Child.prototype = new Parent();
  11. var kid = new Child("Patrick");
  12. kid.name;//"Patrick"
  13. kid.say();//"Patrick"
  14. delete kid.name;
  15. kid.say();//"Adam"

上面代码中。say()被继承了。可以看到,name属性被继承了两次,在删除了kid本身的name属性的副本之后,可以看到输出的是原型链所引出的name.
原型链示意图:

类式继承模式-共享原型

和前面的模式需要调用两次父构造函数不同,下面的模式不涉及调用父构造函数。

这个模式的法则在于,可复用成员应该转移到原型中而不是放在this中,所以,出于继承的目的,任何需要继承的属性和方法都应该放在原型中,所以可以仅将子对象的原型和父对象的设置成相同。代码如下:

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

这种模式可以提供简短而迅速的原型链查询,这是因为所有的对象实际上共享了一个原型。但这也同时是一个缺点,因为如果在继承链下方的某处存在的一个子对象中修改了原型,他会影响到所有父对象和祖先对象。
如下图,下面的子对象和父对象共享了同一个原型,并且可以同等访问say()方法,但子对象没有继承name属性。

javascript代码复用模式(二)的更多相关文章

  1. javascript代码复用模式

    代码复用有一个著名的原则,是GoF提出的:优先使用对象组合,而不是类继承.在javascript中,并没有类的概念,所以代码的复用,也并不局限于类式继承.javascript中创建对象的方法很多,有构 ...

  2. javascript代码复用模式(三)

    前面谈到了javascript的类式继承.这篇继续部分类式继承,及一些现代继承. 类式继承模式-代理构造函数 这种模式通过断开父对象与子对象之间原型之间的直接链接关系,来解决上次说到的共享一个原型所带 ...

  3. 《JavaScript模式》第6章 代码复用模式

    @by Ruth92(转载请注明出处) 第6章:代码复用模式 GoF 在其著作中提出的有关创建对象的建议原则: -- 优先使用对象组合,而不是类继承. 传统模式:使用类继承: 现代模式:"类 ...

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

    介绍 本文介绍的四种代码复用模式都是最佳实践,推荐大家在编程的过程中使用. 模式1:原型继承 原型继承是让父对象作为子对象的原型,从而达到继承的目的: function object(o) { fun ...

  5. 《JavaScript 模式》读书笔记(6)— 代码复用模式2

    上一篇讲了最简单的代码复用模式,也是最基础的,我们普遍知道的继承模式,但是这种继承模式却有不少缺点,我们下面再看看其它可以实现继承的模式. 四.类式继承模式#2——借用构造函数 本模式解决了从子构造函 ...

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

    介绍 任何编程都提出代码复用,否则话每次开发一个新程序或者写一个新功能都要全新编写的话,那就歇菜了,但是代码复用也是有好要坏,接下来的两篇文章我们将针对代码复用来进行讨论,第一篇文避免篇,指的是要尽量 ...

  7. javascript代码复用(四)-混入、借用方法和绑定

    这篇继续说js的现代复用模式:混入.借用方法和绑定. 混入 可以针对前面提到的通过属性复制实现代码复用的想法进行一个扩展,就是混入(mix-in).混入并不是复制一个完整的对象,而是从多个对象中复制出 ...

  8. 《JavaScript 模式》读书笔记(6)— 代码复用模式3

    我们之前聊了聊基本的继承的概念,也聊了很多在JavaScript中模拟类的方法.这篇文章,我们主要来学习一下现代继承的一些方法. 九.原型继承 下面我们开始讨论一种称之为原型继承(prototype ...

  9. javascript代码复用--继承

    由于javascript没有类的概念,因此无法通过接口继承,只能通过实现继承.实现继承是继承实际的方法,javascript中主要是依靠原型链要实现. 原型链继承 原型链继承是基本的继承模式,其本质是 ...

随机推荐

  1. 黄聪:wordpress伪静态的原理

    首先起作用的是配置文件的.htaccess 中的 RewriteEngine OnRewriteBase /RewriteRule ^index\.php$ - [L]RewriteCond %{RE ...

  2. jetty-run运行报错的原因

  3. UVA 272 TEX Quotes

    TEX Quotes 题意: 变引号. 题解: 要想进步,真的要看一本好书,紫书P45 代码: #include<stdio.h> int main() { int c,q=1; whil ...

  4. cf 605B B. Lazy Student 构造 好题

    题意: 一个n个节点的图,有m条边,已知这个图的一个mst 现在如果我们知道这个图的m条边,和知道mst的n-1条边是哪些,问能不能构造出一个满足条件的图 思路:排序+构造 数组deg[i]表示节点i ...

  5. python入门,猜数

    #this is a sample guess program import random guesses_made =0 name = raw_input('Hello! whats your na ...

  6. win764上vs2010+opencv2.4.11安装配置

    1:准备工作 1)opencv的官网下载你所要版本的opencv库文件,运行安装解压到自定义的一个文件夹里(D:\Program Files). 2)安装vs2010. 二:配置 1.计算机环境变量: ...

  7. Idea KeyGen

    import java.math.BigInteger; import java.util.Date; import java.util.Random; import java.util.Scanne ...

  8. Apache Thrift学习之二(基础及原理)

    Apache Thrift 是 Facebook 实现的一种高效的.支持多种编程语言的远程服务调用的框架.本文将从 Java 开发人员角度详细介绍 Apache Thrift 的架构.开发和部署,并且 ...

  9. java中使用正则表达式

    1.用正则表达式分割字符串 Pattern SPLIT2 = Pattern.compile("[,]"); String[] tmpStrings1 = SPLIT2.split ...

  10. 移动应用(手机应用)开发IM聊天程序解决方案

    这个解决方法已经定制下来很久了,上一段时间比较忙,没有时间整这些东西.最近稍微好些,不怎么加班.所以抽空总结下,同时也分享给大家,也算是给大家一个借鉴吧!或许这并不是最好的解决方案,但只要能满足当前需 ...