js中构造函数的继承
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中构造函数的继承相关推荐
- 【JavaScript】js中的原型继承
文章目录 1. 理解继承 2. js中的继承(原型继承) 3. js6种继承方式 3.1 原型链继承 3.2 盗用构造函数 3.3 组合继承 3.4 原型式继承 3.5 寄生式继承 3.6 寄生式组合 ...
- ES6新特性_ES6语法糖_ES5中构造函数的继承---JavaScript_ECMAScript_ES6-ES11新特性工作笔记035
我们先看用es5实现一个构造函数的继承. 我们去用es5的写法写一个Phone这个类 然后给他添加一个Phone.prototype.call = function(){} 添加call的方法. 然后 ...
- js中构造函数与普通函数的区别
构造函数不仅只出现在JavaScript中,它同样存在于很多主流的程序语言里,比如c++.Java.PHP等等.与这些主流程序语言一样,构造函数在js中的作业一样,也是用来创建对象时初始化对象,并且总 ...
- 【继承系列】JS中的组合继承
1.组合继承 既然原型链继承和构造函数继承都有这么多的缺点,我们可以将他们两个结合一下. 看下他们两个的伪代码,该如何组合 // 原型链继承 Child.prototype = new Parent( ...
- js中构造函数的创建
构造函数的创建 方法一 <script type="text/javascript">//1函 2 实 3 属 4 方 5 调function Play(){}//实例 ...
- js 非构造函数的继承 object()方法
$(document).ready(initPage);function initPage() {var Doctor = object(Chinese);Doctor.career = '医生';a ...
- JS中__proto__和prototype都是什么?原型链继承解读
首先要知道,prototype是函数才有的属性,__proto__是每个对象都有的属性 随后,先谈一下 1.什么是prototype? prototype对象是JS实现面向对象的一个重要机制. 在很早 ...
- JS中Prototype属性解释及常用方法
1.prototype的定义 javascript中的每个类都有prototype属性,其prototype属性的解释是:返回对象类型原型的引用.每一个构造函数都有一个属性叫做原型.这个属性非常有用: ...
- 剖析javascript中构造函数
在绝大多数的编程语言中,均存在函数这一概念,其含义大概可以归纳为:包含一定语句,用于完成某些有意义的工作,如处理文本.控制输入输出或计算数值等.通过在程序代码中引入函数名称和所需的参数,可在该程序中执 ...
最新文章
- 一次使用Eclipse Memory Analyzer分析weblogic内存溢出
- Chrome 开发者工具的各种骚技巧
- Win64 驱动内核编程-3.内核里使用内存
- ffmpeg之常用命令的学习
- ASP.NET MVC与RAILS3的比较
- Docker: vmware企业级docker镜像私服--Harbor的搭建
- SQL server 系统优化--通过执行计划优化索引(1) (转)
- input html5 新特性,html5 input 新特性
- xp共享文件win7访问时不能保存密码
- 7个等级 容灾等级_猫奴的10个等级 你的奴性有多高?
- 【基础教程】免疫算法【006期】
- iOS 应用内付费(IAP)开发步骤
- 15.网络协议-Radius协议
- 第三集 怪物学院 第二十章
- APIX_身份证图像识别技术(附代码)
- 风和日丽,幸福如草场广袤无边
- Android 取消蓝牙配对框 实现自动配对
- java 开源 cms FreeCMS1.7发布
- 在百度注册物联网账号,建立设备型与数据型项目
- python2018.9.27内容
热门文章
- HTML学生个人网站作业设计:电影网站设计——迪士尼影视电影(6页) HTML+CSS+JavaScript 简单DIV布局个人介绍网页模板代码 DW学生个人网站制作成品下载
- static与全局变量
- 《PANet:Path Aggregation Network for Instance Segmentation》论文笔记
- 心灵鸡汤可以作为学习材料吗?-好的学习材料的重要性
- 十个数字按从大到小排序
- SSMS18.11安装失败,挂起的重启正在阻止完成安装过程
- Node.js web服务器文件读取
- 浅析ODS与EDW 关系(转载)
- 1044 火星数字 (c语言)
- vue-elemnetUI