关于JS继承关于JS继承关于继承这个概念 , 是由面向对象衍生出来的 。而JS身为一种基于面向对象而设计的语言 , 它和正统的面向对象语言又是有差别的 。
面向对象语言身为面向对象语言需要对开发者提供四种能力:
①:封装 - 把相关的信息(无论数据或方法)存储在对象中的能力;
②:聚集 - 把一个对象存储在另一个对象内的能力;
③:多态 - 编写能以多种方法运行的函数或方法的能力;
④:继承 - 有另一个或多个类得来类的属性和方法的能力;
虽然JS都具备这种能力 , 然而它却和正统的面向对象语言有差异,具体表现主要在第③、④点 。
多态【关于JS继承】多态主要有两种实现形式:
①:重载(编译时多态性) - 方法名相同 , 形参个数或类型不同;
②:重写(运行时多态性) - 在继承中 , 子类重写父类的方法;
这两种形式上JS和java/C#是表现形式是不一样的 。
重载:
// java代码示例public void sum(int n, float m){}public void sum(int n, float m, int t){}public void sum(int n, float m, String t){}在java中这sum方法会分别在不同情况下调用 。
// js代码示例function sum(n,m){}function sum(n,m,t){}在JS中sum方法在前面定义的会被后面定义的覆盖 , 因此JS用相同方法处理不用情况只能在sum方法内部对数据做识别判断了 。
重写:
//java代码示例public class Main {public static void main(String[] args) {Student a = new Student();a.say();}}class person{public void say(){System.out.println("11111");}}class Student extends person{public void say(){System.out.println("22222");}}这里Student继承了person , 对say方法进行了重写 , 虽然重写了say方法 , 但是父类方法不会被改变 。
//js代码示例function A(m){this.m = m;}A.prototype.getM = function(){console.log(100,this.m)}function B(n){this.n = n;}B.prototype = new A(100);B.prototype.getN = function(){console.log(this.n)}let b = new B(200);b.getM();//打印 100,100b.getM = function(){console.log(1)}b.getM();//打印 1A.prototype.getM(); //打印 100,undefinedb.__proto__.__proto__.getM = function(){console.log(0,this.m)}; b.getM();//打印 1A.prototype.getM(); //打印 0,undefined而JS对继承的父类的重写就有点不一样了 , JS是基于原型链的继承 。调用方法或对象时会在原型链中追溯 , 而当在实例b中添加了getM方法时 , 其实是拦截了原型链上的getM,因此这种拦截不会改动到A.prototype.getM , 然而A.prototype.getM又不是绝对的私密的 , 在示例中可以看到利用b.__proto__.__proto__.getM重写getM是会导致A.prototype.getM也被重写的 , 所以js原型链继承中是没有完整意义上的私密属性的 。
继承和其他正统的面向对象语言不一样 , 其他语言的继承一般都是拷贝继承 , 也就是子类会把父类中的方法和属性拷贝的子类中实现继承 , 而JS的继承是把父类的原型放在子类的原型链上 , 利用原型链的查找机制实现继承的 。
而且JS的继承方式也是很多的 , 下面列举一下比较常见的继承方式 。
一、原型链继承function A(m){this.m = m;}A.prototype.getM = function(){console.log(this.m)}function B(n){this.n = n;}B.prototype = new A(100);B.prototype.getN = function(){console.log(this.n)}let b = new B(200);b.getN();//输出 200b.getM();//输出 100特点:
1、非常纯粹的继承关系 , 实例是子类的实例 , 也是父类的实例;
2、父类新增属性或其原型新增属性 , 子类都能访问;
缺点:
1、子类能重写父类方法 , 如:b.__proto__.__proto__.getM = null , 可以改写父类方法;
2、父类的私有属性和公有属性都变成子类的公有属性;
3、继承时方法B原型上原有的方法或属性会丢失 , 如:constructor构造函数;(解决:B.prototype = B);
4、子类创建实例时无法向父类传参;
5、无法实现多继承;
二、构造函数继承function A(m, n){this.m=m;this.n=n;} function B(m, n, t){A.call(this, m, n);this.t=t;} var b = new B(1, 2, 3);console.log(b.m, b.n, b.t);特点:
1、能在子类创建实例时向父类传递参数;
2、可以实现多继承;
缺点:
1、只能继承父类的属性(不继承原型链);
2、创建的实例携带着父类属性 , 臃肿;
三、寄生组合继承function B(n){this.n = n;}B.prototype.getB = function(name){console.log(this.n, name);}function A(m){B.call(this,200)this.m = m;}// 我是旧时代的残党,新时代没有适合承载我的船// (function(){//// 创建一个没有实例方法的类//var Super = function(){};//Super.prototype = B.prototype;////将实例作为子类的原型//A.prototype = new Super();// })();// ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承 。A.prototype = Object.create(B.prototype);A.prototype.constructor = A;A.prototype.getA = function(name){console.log(this.m, name)}var aa = new A(100);aa.getA("A");aa.getB("B");特点:
1、可以继承父类的属性及其原型上的属性;
2、既是子类的实例 , 也是父类的实例;
3、不存在引用属性共享问题;
4、父类可接收传参;
四、ES6的Class实现继承class A{constructor(m){this.m = m;}getM(){console.log(this.m)}}class B extends A{constructor(n){// A.call(this) 报错super(200)this.n = n;}getN(){console.log(this.n)}}// B.prototype = null;不会生效 , 不允许重定向原型let b = new B(100);b.getN();//打印 100b.getM();//打印 200b.__proto__.__proto__.getM = function(){console.log(1)}b.getM();//打印 1ES6中的class继承就是语法糖 , 本质上也是原型链继承的机制 , 也是不能完全保护父类的属性 。
- 春季老年人吃什么养肝?土豆、米饭换着吃
- 三八妇女节节日祝福分享 三八妇女节节日语录
- 老人谨慎!选好你的“第三只脚”
- 校方进行了深刻的反思 青岛一大学生坠亡校方整改校规
- 脸皮厚的人长寿!有这特征的老人最长寿
- 长寿秘诀:记住这10大妙招 100%增寿
- 春季老年人心血管病高发 3条保命要诀
- 眼睛花不花要看四十八 老年人怎样延缓老花眼
- 香槟然能防治老年痴呆症? 一天三杯它人到90不痴呆
- 老人手抖的原因 为什么老人手会抖
