对象之间继承的 5 中方法.
            比如, 现在有一个"动物"对象的构造函数.
            function Animal(){
                this.species = "动物";
            }
            还有一个"猫"对象构造函数
            function Cat(name,color){
                this.name = name;
                this.color = color;
            }
            怎样才能使猫继承动物呢?
            
            一.构造函数绑定
                第一种方法,也是最简单的方法,使用call 或 apply 方法, 将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:

function Cat(name,color){
                    Animal.apply(this, arguments);
                    this.name = name;
                    this.color = color;
                }
                var cat1 = new Cat("大毛","黄色");
                alert(cat1.species);//猫科动物

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>0.2-1 obj</title>
</head>
<body>
<script>
//父构造函数
function Animal(){
this.species = "猫科动物"
} //子构造函数
function Cat(name,color){
Animal.apply(this,arguments);
this.name = name;
this.color = color;
} //构造实例
var cat1 = new Cat("大毛","黑色");
alert(cat1.species);
</script>
</body>
</html>

二.Prototype模式
                第二种方法更常见,使用 Prototype属性.
                如果用"猫"的prototype对象,指向一个Animal的实例,那么所有"猫"的实例,就能继承Animal了.
                
                Cat.prototype = new Animal();
                它相当于完全删除了prototype对象原先的值, 然后赋予一个新值.但是第二行又是什么意思呢?
                Cat.prototype.constructor = Cat;
                原来, 任何一个prototype对象都有一个constructor属性,指向它的构造函数.如果没有"Cat.prototype=new Animal();"这一行,Cat.prototype.constructor是指向Cat的;加了这一行以后,Cat.prototype.constructor指向Animal.
                alert(Cat.prototype.constructor == Animal);//true
                
                cat1使用构造函数Cat生成的,因此我们需要手动纠正,将Cat.prototype对象的contructor值改为Cat,不然就会导致继承链的紊乱.
                
                注: 这是编程中很重要的一点,编程时务必遵守.
                
                如果替换了prototype对象,
                o.prototype = {};
                那么, 下一步必然会成为新的 prototype对象加上constructor属性,并将这个属性指回原来的构造函数.
                o.prototype.constructor = o;

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>0.2-2 </title>
</head>
<body>
<script>
function Animal(){
this.species = "动物";
} function Cat(name,color){
this.name = name;
this.color = color;
}
Cat.prototype = new Animal();
alert(Cat.prototype.constructor);//Animal
Cat.prototype.constructor = Cat;
alert(Cat.prototype.constructor);//Cat var cat1 = new Cat("大毛","黄色");
alert(cat1.species);//动物 </script>
</body>
</html>

三.直接继承prototype
                第三种方法是对第二种方法的改进. 由于Animal对象中, 不变的属性都可以直接写入 Animal.prototype. 所以,我们也可以让 Cat()跳过Aniaml(),直接继承Animal.prototype.
                
                现在, 我们先将Animal对象改写:
                function Animal(){}
                Animal.prototype.species = "动物";
                然后,将 Cat的prototype对象,然后指向Animal的prototype对象,这样就完成了继承.
                
                Cat.prototype = Animal.prototype;
                Cat.prototype.constructor = Cat;
                var cat1 = new Cat("大毛","黄色");
                alert(cat1.species);//动物

与前一种方法相比, 这样做的优点是效率比较高(不用执行和建立Animal的实例了),比较省内存. 缺点是Cat.prototype和Animal.prototype现在指向了同一个对象,那么任何对Cat.prototype的修改,都会反映到Animal.prototype.
                所以,上面这一段代码其实是有问题的.请看第二行
                Cat.prototype.constructor = Cat;
                这一句话实际上把Aniaml.prototype对象的constructor属性也改掉了!
                alert(Animal.prototype.constructor);//Cat
                
            四.利用空对象作为中介
                由于"直接继承prototype"存在上述的缺点,所以就有第四种方法,利用一个空对象作为中介.

var F = function(){};
                   F.prototype = Animal.prototype;
                   Cat.prototype = new F();
                   Cat.prototype.constructor = Cat;
                
                F是空对象,所以几乎不占内存.这时,修改Cat的prototype对象,就不会影响到Animal的prototype对象.
                alert(Animal.prototype.constructor);//Animal
                
                
                我们将上边的方法,封装成一个函数,便于使用.
                function extend(Child,Parent){
                      var F = function(){};
                      F.prototype = Parent.prototype;
                      Child.prototype = new F();
                      Child.prototype.constructor = Child;
                      Child.uber = Parent.prototype;
                 }

//使用方法如下:
             extend(Cat,Animal);
                var cat1 = new Cat("大毛","黄色");
                alert(cat1.species);//动物
                这个extend函数,就是YUI库如何实现继承的方法.
                
                另外,说明一点,函数体最后一行
                Child.uber = Parent.prototype;
                意思是为子对象设一个uber属性, 这个属性直接指向父对象的prototype属性.这等于在子对象上打开一条通道,可以直接调用父对象的方法.这一行放在这里,只是为了实现继承的完备性,纯属备用性质.
                
            五.拷贝继承
                上面采用prototype对象,实现继承.我们也可以换一种思路,纯粹采用"拷贝"方法实现继承.简单说,如果把父对象的所有属性和方法,拷贝进子对象,不也能够实现继承吗?
                
                首先,还是把Animal的所有不变属性, 都放到它的prototype对象上.
                function Animal(){};
                 Animal.prototype.species = "动物";
                然后,再写一个函数,实现属性拷贝的目的.
                function extend2(Child, Parent){
                      var p = Parent.prototype;
                      var c = Child.prototype;
                      for(var i in p){
                          c[i] = p[i];
                      }
                      c.uber = p;
                }
                这个函数的作用,就是将父对象的prototype对象中的属性,一一拷贝给Child对象的prototype对象.
                
                使用的时候,这样写:
                extent2(Cat,Animal);
                 var cat1 = new Cat("大毛","黄色");
                 alert(cat1.species);//动物

原文链接:http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_inheritance_continued.html

JS面向对象编程(二):构造函数的继承的更多相关文章

  1. (二)Javascript面向对象编程:构造函数的继承

    Javascript面向对象编程:构造函数的继承   这个系列的第一部分,主要介绍了如何"封装"数据和方法,以及如何从原型对象生成实例. 今天要介绍的是,对象之间的"继承 ...

  2. Javascript面向对象编程:构造函数的继承

    今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...

  3. js面向对象编程(第2版)——js继承多种方式

    附带书籍地址: js面向对象编程(第2版)

  4. Js面向对象编程

    Js面向对象编程 1.     什么是面向对象编程? 我也不说不清楚什么是面向对象,反正就那么回事吧. 编程有时候是一件很快乐的事,写一些小游戏,用编程的方式玩游戏等等 2.     Js如何定义一个 ...

  5. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

  6. 带你一分钟理解闭包--js面向对象编程

    上一篇<简单粗暴地理解js原型链--js面向对象编程>没想到能攒到这么多赞,实属意外.分享是个好事情,尤其是分享自己的学习感悟.所以网上关于原型链.闭包.作用域等文章多如牛毛,很多文章写得 ...

  7. js面向对象编程 ---- 系列教程

    原 js面向对象编程:数据的缓存 原 js面向对象编程:如何检测对象类型 原 js面向对象编程:if中可以使用那些作为判断条件呢? 原 js面向对象编程:this到底代表什么?第二篇 原 js面向对象 ...

  8. C++ Primer 学习笔记_72_面向对象编程 --句柄类与继承[续]

    面向对象编程 --句柄类与继承[续] 三.句柄的使用 使用Sales_item对象能够更easy地编写书店应用程序.代码将不必管理Item_base对象的指针,但仍然能够获得通过Sales_item对 ...

  9. JS面向对象编程,对象,属性,方法。

    document.write('<script type="text/javascript" src="http://api.map.baidu.com/api?v ...

  10. Python进阶之面向对象编程(二)

    Python面向对象编程(二) .note-content {font-family: "Helvetica Neue",Arial,"Hiragino Sans GB& ...

随机推荐

  1. 支持向量机 (二): 软间隔 svm 与 核函数

    软间隔最大化(线性不可分类svm) 上一篇求解出来的间隔被称为 "硬间隔(hard margin)",其可以将所有样本点划分正确且都在间隔边界之外,即所有样本点都满足 \(y_{i ...

  2. CentOS7.x mini安装OVS

    命令均在root用户下运行: 一.关闭防护墙及selinux sed -i '/SELINUX/s/enforcing/disabled/g' /etc/selinux/config setenfor ...

  3. 消息驱动式微服务:Spring Cloud Stream & RabbitMQ

    1. 概述 在本文中,我们将向您介绍Spring Cloud Stream,这是一个用于构建消息驱动的微服务应用程序的框架,这些应用程序由一个常见的消息传递代理(如RabbitMQ.Apache Ka ...

  4. flume1.9 用户指南(中文版)

    概述 Apache Flume是一个分布式,可靠且可用的系统,用于有效地从许多不同的source收集,聚合和移动大量日志数据到集中式数据存储. Apache Flume的使用不仅限于日志数据聚合.由于 ...

  5. 驰骋工作流引擎ccflow-ccbpm工作流引擎sdk表单装载逻辑处理注意事项

    cbpm工作流引擎sdk表单装载逻辑处理注意事项 关键字:驰骋工作流引擎 sdk表单 装载接口调用   说明:如果您要采用ccbpm的sdk表单开发,在表单 加载前您需要调用一个接口来获得当前节点的信 ...

  6. 深入理解Java虚拟机笔记——虚拟机类加载机制

    目录 概述 动态加载和动态连接 类加载的时机 类的生命周期 被动引用 例子一(调用子类继承父类的字段) 例子二(数组) 例子三(静态常量) 类加载的过程 加载 验证 准备 解析 符号引用 直接引用 初 ...

  7. Codeforces 758B:Blown Garland(模拟)

    http://codeforces.com/problemset/problem/758/B 题意:给出一个字符串,每4个位置对应一个颜色,如果为‘!’的话,代表该灯泡是坏的,问最后每个颜色坏的灯泡的 ...

  8. 关于ArrayList的扩容机制

    关于ArrayList的扩容机制 ArrayList作为List接口常用的一个实现类,其底层数据接口由数组实现,可以保证O(1) 复杂度的随机查找, 在增删效率上不如LinkedList,但是在查询效 ...

  9. 【POJ - 1979 】Red and Black(dfs+染色)

    -->Red and Black Descriptions: 有个铺满方形瓷砖的矩形房间,每块瓷砖的颜色非红即黑.某人在一块砖上,他可以移动到相邻的四块砖上.但他只能走黑砖,不能走红砖. 敲个程 ...

  10. JS格式化JSON后的日期

    序列化后日期变成了 /Date(1494524134000+0800)\ 这种格式 不能正常显示了 但也不能为了这个吧所有服务的DateTime字段都改成String类型 于是找了一个JS的扩展方法来 ...