function Animal(){this.species = "动物";this.zoomName = '东郊公园';this.age = 2;
}
Animal.prototype.age = 3;
function Cat(name, color){this.name = name;this.color = color;
}
// 怎么使得“猫”继承“动物”呢?

假设有业务场景:猫需要继承动物的属性,如何实现?

可以用以下四种方式:

  • 构造函数绑定:使用call或者apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:

Father.apply(this, arguments); 或者 Father.call(this, arguments);

显然,这种实现方式下,猫的实例对象完全继承了动物的所有属性。

/* 第一种:构造函数绑定 。最简单的方法。
* 使用call或者apply方法,将父对象的构造函数绑定在子对象上,即在子对象构造函数中加一行:
* 父.apply(this, arguments); 或  父.call(this, arguments);
*/
/* Cat举例 */
function Cat2(name, color){
//  Animal.apply(this, arguments);Animal.call(this, arguments);this.name = name;this.color = color;
}
var catMao = new Cat2('咪咪', '白色');
console.log(catMao);

  • prototype模式:使得子类的prototype指向父类的任意一个实例,即:在定义子对象的构造函数定义完成后,加两行:

Son.prototype = new Father ();

Son.prototype.constructor = Son;


/* Cat举例 *//* 第二种:prototype模式。最常见的方法。
如果“猫”的prototype对象,指向一个Animal的实例,那么所有“猫”的实例,就能继承Animal了。
特别的:因为每一个实例也有一个constructor属性,默认调用prototype对象的constructor属性,而且任何一个prototype对象都有一个constructor属性,指向它的构造函数,如果替换了构造函数o的prototype对象(默认是:o.prototype = {}),那么,下一步必然是为新的prototype对象加上constructor属性,并将这个属性指回原来的构造函数o。
o.prototype.constructor = o;
*/
// Cat举例
function Cat3(name, color){this.name = name;this.color = color;
}
console.log('Cat3****prototype=', Cat3.prototype); // {}
Cat3.prototype = new Animal();
console.log('Cat3****继承Animal后***prototype=;', Cat3.prototype); //  Animal { species: '动物', zoomName: '东郊公园' }
console.log('Cat3*****继承Animal后***构造函数=', Cat3.prototype.constructor); //  [Function: Animal]/* 因为上一步修改Cat3的prototype,导致继承链紊乱因此手动纠正,使得Cat3的原型的构造函数还是Cat3 */
Cat3.prototype.constructor = Cat3;
console.log('Cat3****先继承Animal****再纠正回来Cat3***prototype=', Cat3.prototype); //  Animal { species: '动物', zoomName: '东郊公园' }
console.log('Cat3*****先继承Animal****再纠正回来Cat3****构造函数=', Cat3.prototype.constructor); //  [Function: Cat3]let mao3 = new Cat3('猫3','黑色');
console.log('Cat3继承了Animal后的****cat3实例=', mao3); // { name: '猫3', color: '黑色' }
console.log('Cat3实例描述=', `我的动物园名字:${mao3.zoomName},我是:${mao3.species},我的年龄:${mao3.age},我的名字:${mao3.name},我的颜色:${mao3.color}`); // 我的动物园名字:东郊公园,我是:动物,我的年龄:2,我的名字:猫3,我的颜色:黑色

显然,以方式二实现继承后,"猫"的实例对象,本身没有Animal的实例属性(age,zoomName,species)。但是,为什么Cat3实例能够取到他们呢?原因是:原型链继承。即:访问实例本身没有的属性,那么就在它的原型链上查找,即会找到自己从Animal继承的prototype里面,从而可以访问到“age,zoomName,species”这几个属性了。

  • 直接继承prototype:第三种方法是对第二种方法的改进。由于Animal对象中,不变的属性都可以直接写入Animal.prototype。所以,我们可以让Cat()跳过Animal(),直接继承Animal.prototype。

第一步:将Father(父构造函数)改写成一个空函数,并抽离Father的不变属性,并写入到prototype上。即:​​​​​​​

Father(){}

Father.prototype.commonProName= value;

第二步:将Cat的prototype对象指向Animal的prototype对象,并且纠正Cat的构造函数;这样就完成了继承。即:

Son.prototype=Father.prototype;

Son.prototype.constructor = Son;

function Animal1 () {}
Animal1.prototype.species = '动物1';
Animal1.prototype.zoomName = '东郊公园1';
Animal1.prototype.age = 4;
console.log('Cat继承前的****prototype=',Cat.prototype);
console.log('Cat继承前的****constructor=',Cat.prototype.constructor);// 2、直接继承prototype:将Cat的prototype对象指向Animal1的prototype对象,并必须纠正Cat的构造函数,这样就完成了继承。
function Cat(name, color){this.name = name;this.color = color;
}
Cat.prototype.catSpecies = "加菲猫";
Cat.prototype = Animal1.prototype;
console.log('Cat继承Animal1的prototype后*****prototype=',Cat.prototype);
console.log('Cat继承Animal1的prototype后的*****constructor=',Cat.prototype.constructor);// 注意:既然替换了某个prototype对象,必须要使得新的prototype加上构造函数,并且constructor指向原来的构造函数。Cat.prototype.constructor = Cat;
console.log('Cat继承Animal1的prototype后,纠正的*****constructor=',Cat.prototype.constructor);var mao4 = new Cat('猫4','蓝色');
console.log('Cat继承后的****cat实例=', mao4);
console.log('Cat4实例描述=', `我是可爱的${mao4.species},来自${mao4.zoomName}动物园,我${mao4.age}岁了;我属于${mao4.catSpecies},取名为${mao4.name},有着漂亮的${mao4.color}毛。`);

思考:

为什么猫的种类为undefined了?

分析:

在prototype赋值语句执行后,Cat本身的protptype被完整替换了,所以继承后的prototype里面再无“catSpecies”属性,仅是有Animal.prototype包含的属性。那么自然也访问不到了。

解决:

可以将它们两句调换位置,即可:

Cat.prototype = Animal1.prototype;

Cat.prototype.catSpecies = "加菲猫";

特点:效率高,省内存,副作用大

副作用:

Son.prototype与Father.prototype指向同一个对象,当修改任何一个是都会影响另一个,这是我们不想看到的。

那如何避免这个副作用呢?请看第四种:

  • 利用空对象作为Son和Father的中介,实现继承。即:

逐步分析:

/* 第四种: 用空对象作为Son和Father的继承中介。弥补了第三种方式存在的副作用。*/
function Animal(){this.species = "动物";this.zoomName = '东郊公园';this.age = 2;
}
Animal.prototype.animalProp = 3;
function Cat(name, color){this.name = name;this.color = color;
}
// 1、定义一个空函数,进而可以产生一个prortotype空对象。
var F = function (){};
// 2、使得空对象的prototype与Father.prototype指向同一个对象(完全拷贝prototype),即F继承了Animal。
F.prototype = Animal.prototype; // 直接继承prototype
F.prototype.fProp="123123"; // 此时也改了Animal的prototype
// 检查F的prototype和constructor
console.log('F继承Animal的prototype后的*****prototype=',F.prototype);
console.log('F继承Animal的prototype后的*****constructor=',F.prototype.constructor);// 3、使Cat的prototype指向F的一个实例。它是完全删除了Cat的prototype 对象原先的值,然后赋予一个新值(F的空prototype)。那么Cat就可以继承到F。
Cat.prototype = new F();
// 检查Cat的prototype和constructor
console.log('Cat继承F的prototype后的*****prototype=',Cat.prototype);
console.log('Cat继承F的prototype后的*****constructor=',Cat.prototype.constructor);
// 4、纠正构造函数指向原来的函数。
Cat.prototype.constructor = Cat;
//改变Cat的prototype
Cat.prototype.catSize="small"; // 此时,仅仅改了自己的prototype
Cat.uber = Animal.prototype;
console.log('Cat继承F的prototype后纠正的*****constructor=',Cat.prototype.constructor);// 检查大家的prototype
console.log('Animal最后的prototype=',Animal.prototype);
console.log('F*****最后的prototype=',F.prototype);
console.log('Cat最后的prototype=',Cat.prototype);
var cat5 = new Cat();
// 检查一下Cat实例的属性有哪些
for(let key in cat5){console.log('猫的属性枚举****************:',key);// name、color、constructor来自Cat// catSize来自Cat.prototype// ...
}
console.log(cat5.species); // undefined,无法访问Animal的私有属性

cat5的属性:构造函数(Cat)里面私有的,constructor,继承自F的prototype里面的,继承自Animal的prototype里面的。

那么,第四种方法,可以简化实现为以下的内容:

function Animal(){this.species = "动物";this.zoomName = '东郊公园';this.age = 2;
}
Animal.prototype.animalProp = 3;
function Cat(name, color){this.name = name;this.color = color;
}function extendsHandle(Father,Son){console.log('handler:',Father,Son);var F = function(){};F.prototype = Father.prototype;F.prototype.fProp = "123";Son.prototype = new F();Son.prototype.constructor = Son;Son.prototype.sonProp="abc";Son.uber= Father.prototype;// uber属性类似super。
}
extendsHandle(Animal, Cat);
var cat5 =new Cat('猫5', "绿色");
console.log('Cat的实例:', cat5);
// cat5没有Animal的三个私有属性。
console.log('Cat5的动物园名称:', cat5.zoomName);for(let key in cat5){console.log('Cat的实例属性有:', key);
}

希望大家多多批评指正。谢谢!

js中构造函数的继承相关推荐

  1. 【JavaScript】js中的原型继承

    文章目录 1. 理解继承 2. js中的继承(原型继承) 3. js6种继承方式 3.1 原型链继承 3.2 盗用构造函数 3.3 组合继承 3.4 原型式继承 3.5 寄生式继承 3.6 寄生式组合 ...

  2. ES6新特性_ES6语法糖_ES5中构造函数的继承---JavaScript_ECMAScript_ES6-ES11新特性工作笔记035

    我们先看用es5实现一个构造函数的继承. 我们去用es5的写法写一个Phone这个类 然后给他添加一个Phone.prototype.call = function(){} 添加call的方法. 然后 ...

  3. js中构造函数与普通函数的区别

    构造函数不仅只出现在JavaScript中,它同样存在于很多主流的程序语言里,比如c++.Java.PHP等等.与这些主流程序语言一样,构造函数在js中的作业一样,也是用来创建对象时初始化对象,并且总 ...

  4. 【继承系列】JS中的组合继承

    1.组合继承 既然原型链继承和构造函数继承都有这么多的缺点,我们可以将他们两个结合一下. 看下他们两个的伪代码,该如何组合 // 原型链继承 Child.prototype = new Parent( ...

  5. js中构造函数的创建

    构造函数的创建 方法一 <script type="text/javascript">//1函 2 实 3 属 4 方 5 调function Play(){}//实例 ...

  6. js 非构造函数的继承 object()方法

    $(document).ready(initPage);function initPage() {var Doctor = object(Chinese);Doctor.career = '医生';a ...

  7. JS中__proto__和prototype都是什么?原型链继承解读

    首先要知道,prototype是函数才有的属性,__proto__是每个对象都有的属性 随后,先谈一下 1.什么是prototype? prototype对象是JS实现面向对象的一个重要机制. 在很早 ...

  8. JS中Prototype属性解释及常用方法

    1.prototype的定义 javascript中的每个类都有prototype属性,其prototype属性的解释是:返回对象类型原型的引用.每一个构造函数都有一个属性叫做原型.这个属性非常有用: ...

  9. 剖析javascript中构造函数

    在绝大多数的编程语言中,均存在函数这一概念,其含义大概可以归纳为:包含一定语句,用于完成某些有意义的工作,如处理文本.控制输入输出或计算数值等.通过在程序代码中引入函数名称和所需的参数,可在该程序中执 ...

最新文章

  1. 一次使用Eclipse Memory Analyzer分析weblogic内存溢出
  2. Chrome 开发者工具的各种骚技巧
  3. Win64 驱动内核编程-3.内核里使用内存
  4. ffmpeg之常用命令的学习
  5. ASP.NET MVC与RAILS3的比较
  6. Docker: vmware企业级docker镜像私服--Harbor的搭建
  7. SQL server 系统优化--通过执行计划优化索引(1) (转)
  8. input html5 新特性,html5 input 新特性
  9. xp共享文件win7访问时不能保存密码
  10. 7个等级 容灾等级_猫奴的10个等级 你的奴性有多高?
  11. 【基础教程】免疫算法【006期】
  12. iOS 应用内付费(IAP)开发步骤
  13. 15.网络协议-Radius协议
  14. 第三集 怪物学院 第二十章
  15. APIX_身份证图像识别技术(附代码)
  16. 风和日丽,幸福如草场广袤无边
  17. Android 取消蓝牙配对框 实现自动配对
  18. java 开源 cms FreeCMS1.7发布
  19. 在百度注册物联网账号,建立设备型与数据型项目
  20. python2018.9.27内容

热门文章

  1. HTML学生个人网站作业设计:电影网站设计——迪士尼影视电影(6页) HTML+CSS+JavaScript 简单DIV布局个人介绍网页模板代码 DW学生个人网站制作成品下载
  2. static与全局变量
  3. 《PANet:Path Aggregation Network for Instance Segmentation》论文笔记
  4. 心灵鸡汤可以作为学习材料吗?-好的学习材料的重要性
  5. 十个数字按从大到小排序
  6. SSMS18.11安装失败,挂起的重启正在阻止完成安装过程
  7. Node.js web服务器文件读取
  8. 浅析ODS与EDW 关系(转载)
  9. 1044 火星数字 (c语言)
  10. vue-elemnetUI