JS--我发现,原来你是这样的JS:面向对象编程OOP[3]--(JS继承)
一、面向对象编程(继承)
这篇博客是面向对象编程的第三篇,JS继承。继承顾名思义,就是获取父辈的各种"财产"(属性和方法)。
怎么实现继承?
我们的JavaScript比较特别了,主要通过原型链实现继承的。
下面介绍各种实现继承的方式:原型链继承,借用构造函数,组合继承,原型式继承,寄生式继承,寄生组合式继承。
二、实现继承方式
1.原型链方式
原型我们都知道,每个构造函数都有一个原型对象(prototype),用于存放共享的属性方法。
原型链继承原理:我们要继承一个父类,那就把这个子类的原型对象指向父类的实例就行了。
a.代码:
//创建父类构造函数
function Father(){this.fristName = "Father";
}
//给父类的原型对象添加方法
Father.prototype.getFatherName = function(){return this.fristName ;
}//创建子类构造函数
function Son(){this.name = 'jack';
}
//重点这行:把子类的原型对象指向父类实例实现继承
Son.prototype = new Father();//我们还可以为子类添加原型方法
Son.prototype.getName = function(){return this.name;
}//测试一下,创建一个子类的实例
var s1 = Son();
s1.getFaterName(); //Father 继承了爸爸的名字了!
b.一些特别注意的地方:
1.上面我们看到为子类原型添加方法getName,它在子类原型对象指向父类实例后,也一定要在这句话后面,如果在前面的话,这方法会被覆盖的。因为子类原型对象指向父类实例时相当于重写子类原型对象。
2.为子类原型添加方法式不能用字面量的方式,这样会重写已经继承类父类的原型对象。
c.原型链继承的问题:
很明显的,继承的属性方法都在子类的原型对象里面,那么里面的属性方法都是共享的,这明显不是符合我们平常要求。
2.借用构造函数
借?是的,借一下父类的构造函数,怎么借?那就使用call或者apply方法吧。
借用构造函数原理: 就在子类创建构造函数时内部调用父类的构造函数。
代码演示:
//父类(父类是相对来说的,大家注意一下噢)
function Father(){this.colors = ['red','green'];
}
//子类
function Son(){//重点这行:内部调用父类构造函数,this是指向未来创建Son的实例Father.call(this);
}//测试一下,继承了父类的属性了,并且属性不会共享噢
var s1 = new Son();
s1.colors.push('blue');
console.log(s1.colors); ['red','green','blue']//s2实例的colors不会被影响
var s2 = new Son();
console.log(s2.colors); ['red','green']
这里的借用构造函数可以实现属性和方法不会被共享,因为属性在构造函数中,而不是在原型对象中。但是这也说明这种方式没办法共享方法的。
3.组合继承(最常用)
组合继承=原型链继承+借用构造函数继承,没错就结合两种方法就好了。
组合继承原理:实例共享的属性方法:我就原型链继承;实例私用的属性方法:我就借用构造函数(结合两者的优点)
代码演示:
//父类
function Father(name){this.name = name;this.colors = ['red','green'];
}
//父类原型对象
Father.pototype.sayName = function(){console.log(this.name);
}
//子类
function Son(name,age){//借用父类构造函数Father.call(this,name);this.age = age;
}
//子类原型指向父类实例,原型链继承
Son.prototype = new Father();
Son.prototype.constructor = Son; //让子类的原型只向子类构造函数
Son.prototype.sayAge = function(){console.log(this.age);
}//创建实例对象
var s1 = new Son('Mc ry',22);
var s2 = new Son('yy',20);
//继承了父类方法,sayName是共享的
s1.sayName(); //mc ry
s2.sayName(); //yy
//继承colors,每个实例私有
s1.colors.push('blue');
console.log(s1.colors); ['red','green','blue']
console.log(s2.colors); ['red','green']
可能有的疑惑:在原型链继承那里,子类原型对象指向类父类的实例,应该继承了所有的属性和方法啊,那应该都是共享的,但为什么colors,name属性不会共享呢?
原因:在调用借用构造函数时,属性在子类新实例中创建了,也就是在子类实例中已经有的父类属性就不用继续到原型对象中查找了,也就是屏蔽了,所以不会共享了。
4.原型式继承
这是道格拉斯·克罗克福提出的一个方式,他提出一个函数object() 来简单实现不用构造函数的继承
代码演示:
//object函数,传入一个对象
function object(o){//创建一个空的构造函数function F(){};//这个空构造函数的原型对象指向o这个对象F.prototype = o ;//返回F的实例对象return new F();
}
认真读这段代码可以知道,这个函数最终返回一个对象,这个对象拥有传入对象o的全部属性和方法。从而实现了继承。
//一个对象
var person = {name : 'ry',sayName : function(){console.log(this.name);}
}//children对象继承了person对象所有的属性方法
var children = object(person);
原型式继承方式的出现,可以不用创建构造函数都能继承另一个对象的属性方法。但是很明显,所用属性都是共享的。
ES5中有个object.create()方法的作用和上面的object()一样的。
5.寄生式的继承
寄生式其实和利用了原型式,都要使用到object函数,但不同的是寄生式中新的对象能够添加自己的方法。
function creatAnother(o){//调用object继承ovar obj = object(o);//还可以添加自己想要的方法obj.sayHi = function (){console.log('hi');}//返回这个对象retrun obj;}//新的对象继承了personvar anotherPerson = creatAnother(person);//继承后能使用person的方法anotherPerson.sayHi(); //"hi"
6.寄生组合式继承(最理想)
上面组合式方式中虽然是最常用的,但有追求的还是会继续优化它。因为组合方式中也有不够好的地方:
一方面:我们可以看到调用了两次父类的构造函数。(一次是原型链继承中子类原型对象指向父类实例时,一次是借用构造函数中)
另一方面:就是上面疑惑,子类的原型中拥有父类已经有全部属性,但我们又要在调用子类构造函数时重写部分属性。
所以寄生组合方式就解决了上面,通过一个函数来代替组合方式中的原型链继承。
代码演示:
//主要是这个函数,实现子类原型对象只继承父类原型对象中的属性
function inheritPrototype(subType,superType){//利用上面的Object函数,将父类的原型赋予prototype变量var prototype = object(superType.prototype);//将prototype的构造函数重新指向子类prototype.constructor = subType;//将prototype给sub的原型对象subType.prototype = prototype;
}//将前面的组合继承改写
//父类
function Father(name){this.name = name;this.colors = ['red','green'];
}
//父类原型对象
Father.pototype.sayName = function(){console.log(this.name);
}
//子类
function Son(name,age){//借用父类构造函数Father.call(this,name);this.age = age;
}
//(这行用inheritPrototype函数替换)子类原型指向父类实例,原型链继承
inheritPrototype(Son, Father);
Son.prototype.sayAge = function(){console.log(this.age);
}
寄生组合式的继承方式是最理想的方式,它使得子类构造函数继承父类构造函数的属性,子类的原型对象继承父类原型对象的属性和方法。
三、小结
1.这次博客讲述了在js中是如何实现继承的,有很多中方式,但主要的是组合方式和寄生组合方式。继承后我们能够使用父类的属性和方法,增加了代码的重用性。
2.了解js继承作用:有助于我们去阅读一些框架的源码,可能本次代码有点难以理解,我打上了大量的注释,供大家一起阅读,还是那句话,多看几遍,其义自见。如果觉得有收获,就点个赞吧,关注我吧。
- 细心的朋友可能发现,我把文章的样式修改了,类似Markdown风格咯,看起来比较清爽,舒服。
同系列几篇:
第一篇:JavaScript--我发现,原来你是这样的JS(一)(初识)
JS--我发现,原来你是这样的JS:面向对象编程OOP[1]--(理解对象和对象属性类型)
JS--我发现,原来你是这样的JS:面向对象编程OOP[2]--(创建你的那个对象吧)
我发现,原来你是这样的JS全部文章汇总(点击此处)
本文出自博客园:http://www.cnblogs.com/Ry-yuan/
作者:Ry(渊源远愿)
欢迎转载,转载请标明出处,保留该字段。
转载于:https://www.cnblogs.com/Ry-yuan/p/7841515.html
JS--我发现,原来你是这样的JS:面向对象编程OOP[3]--(JS继承)相关推荐
- JS基础——面向对象编程OOP
面向对象编程有三大特点:封装.继承.多态.JS中不存在多态的概念,因此JS不是面向对象的语言,是基于对象的语言. 封装 将一个实体的信息.功能等都封装在一个对象上的特性.JS中的构造函数和类都是封装d ...
- JavaScript学习笔记---面向对象编程-JS高级部分(pink老师)
目录 一.面向对象编程介绍 1.1 两大编程思想 1.面向过程编程POP(Process-Oriented Programming) 2.面向对象编程OOP(Object Oriented Progr ...
- JS面向对象编程三大特征
JS面向对象编程三大特征 JS面向对象的三大特征为封装.继承.多态.下面分别进行介绍: 封装 封装是指创建一个对象集中保存一个事物的属性与功能 继承 继承是指父亲的成员,孩子无需重复创建就可直接使用. ...
- 在谷歌浏览器安装了Vue.js devtools发现不能用显示Vue.js is not detected
在谷歌浏览器安装了Vue.js devtools发现不能用显示Vue.js is not detected 学习vue框架的时候,在谷歌浏览器安装了Vue.js devtools插件,写了一个入门的h ...
- JS中的面向对象编程
JS中的面向对象编程 小课堂 目录 1.背景介绍 2.知识剖析 3.常见问题 4.解决方案 5.编码实战 6.扩展思考 7.参考文献 8.更多讨论 1.背景介绍 什么是对象? ECMA-262把对象定 ...
- js异步等待完成后再进行下一步操作_彻底搞懂JS事件中的循环机制 Event Loop
我们都知道JavaScript是单线程语言,就是因为单线程的特性,就不得不提js中的同步和异步 一.同步和异步 所谓单线程,无非就是同步队列和异步队列,js代码是自上向下执行的,在主线程中立即执行的就 ...
- 简单粗暴地理解js原型链–js面向对象编程
简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...
- 云笔记项目-补充JS面向对象编程基础知识
简单介绍: 此部分知识为在做云笔记项目中补充,因为云笔记项目中涉及到前端js,里面写了很多js脚本,用到了创建js属性和方法,在js中直接声明的属性和方法最终都会变成window的对象,即其成为了全局 ...
- VSCode自定义代码片段9——JS中的面向对象编程
JavaScript的面向对象编程 {// JS'OOP// 9 如何自定义用户代码片段:VSCode =>左下角设置 =>用户代码片段 =>新建全局代码片段文件... =>自 ...
- JS面向对象编程(OOP)
什么是JS面向对象编程(OOP)? 用对象的思想去写代码,就是面向对象编程. 上面这张图就是一个对象,紫色部分就是车的属性,黄色部分就是修改车的方法: 把他们集合到一个构造函数内,就是这样的 func ...
最新文章
- 在FFT分析在而立之年的展望与总结
- Runnable和Thread的区别
- 管道的另一端上无任何进程。_历史上突然消失的二位牛人,其下落无任何记载...
- JDK 14的新特性:switch表达式
- 优秀渗透工具资源整理(持续更新)
- 四,Golang 交叉编译
- 程序员过关斩将--论系统设计的高可扩展性
- Node.js umei图片批量下载Node.js爬虫1.00
- java json序列化日期类型
- 计算机usb端口没反应,usb接口没反应,小编教你电脑usb接口没反应怎么解决
- 微软手环2服务器,微软手环2评测 数据狂的最爱
- 附件携马之CS免杀shellcode过国内主流杀软
- OneDrive 正在登录
- Webpack中 的css-loader和less-loader
- AJAX异步判断注册用户名是否重复
- 关于计算机的英语演讲稿三分钟,关于自信的英语三分钟演讲稿
- nginx配置防止域名恶意解析
- 了解 HTTPS(二) —— 通信加密
- 医学研究生常用软件介绍
- 【2021年1月】RT-Thread社区简报
热门文章
- CentOS 6.7安装Spark 1.5.2
- TLS总结(上)——我们为啥需要TLS
- oracle主机修改IP后客户端无法连接
- 配置管理小报091103-2: CVS中的tag规则
- 如何在network monitor中查找试图建立TCP连接的帧?
- 19.MongoDB值distinct性能验证
- mysql的瓶颈_MySQL 瓶颈分析及优化
- layer弹窗在键盘按回车将反复刷新_人生减负指南——iPad Pro+妙控键盘上手体验...
- idea javafx添加maven_IntelliJ IDEA使用之JavaFX
- python课程报告模板_Python制作WORD报告