继承的概念

谈到继承,就不得不谈到类和对象的概念

是抽象的,它是拥有共同的属性和行为的抽象实体。

对象是具体的,它除了拥有类共同的属性和行为之外,可能还会有一些独特的属性和行为。

打个比方:

人类,就是一个抽象类,假设人类的共同属性是有手、有脚、有嘴巴,共同的行为是说话。

小明,就是一个具体的对象,他是人类,因此他拥有人类的共同属性和行为(有手有脚有嘴巴+会说话),除此之外,他还拥有一些独特的个性化的属性和行为,比如说他喜欢唱跳rap篮球。

那么什么是继承呢?

类的继承,子类继承父类之后,子类就拥有了父类的属性和行为。

在代码层面,就是子类通过继承来复用父类的代码。

打个比方:

人类,就是一个抽象类,假设人类的共同属性是有手、有脚、有嘴巴,共同的行为是说话。

新人类,继承了人类,它就拥有了人类的共同属性和行为(有手有脚有嘴巴+会说话),可以复用人类的代码。除此之外,他还可以拥有一些自己的独特属性和行为,比如说超能力之类的。

在es6之前,js的构造函数式面向对象语法与传统面向对象编程语言有所区别,js未在语法层面支持继承的操作。因此,js需要通过原型链特性,call、apply等的应用来实现继承。

js继承的最佳实践是“寄生组合式继承”,它结合了原型继承借用构造函数继承

原型继承(继承私有属性和原型属性,但无法传参)

根据原型链的特性:在访问实例对象属性的时候,如果没有找到这个属性,就会顺着__proto__去原型中查找。

因此,我们利用这一点,可以将子类构造函数的prototype(原型)指向父类的实例,当子类对象中找不到属性的时候,就会去父类实例中查找,从而让子类继承复用了父类的属性。

// 父类构造函数
function Father() {
this.name = 'father';
} // 子类构造函数
function Child() {
this.age = 16;
} // 子类的prototype指向父类的实例
Child.prototype = new Father(); var child = new Child();
console.log(child.name); // father
console.log(child.age); // 16

原型继承的实现:子类的prototype = 父类的实例。

原型继承特点:可以继承父类的私有属性和原型属性

原型继承的缺点:无法向父类构造函数传参。

借用构造函数继承(可以传参,继承私有属性,但不能继承原型属性)

为了解决原型继承不能向父类构造函数传参的缺点。

借用构造函数继承,使用call或apply方法在子类构造函数中调用父类的构造函数,从而让子类继承父类的私有属性

// 父类构造函数
function Father(name) {
this.name = name;
} // 往父类原型上放一个say方法
Father.prototype.say = function() {
return 'i am your father';
} // 子类构造函数
function Child(name) {
Father.call(this, name);
this.age = 16;
} Child.prototype.sex = 'man'; var child = new Child('child');
// 调用父类的私有属性name
console.log(child.name); // child
// 调用父类的原型属性say
// console.log(child.say()); // child.say is not a function
// 调用子类的私有属性age
console.log(child.age); // 16
// 调用子类的原型属性sex
console.log(child.sex); // man

借用构造函数继承的实现:构造函数的this指向是指向实例,而在子类构造函数中使用call/apply,将父类构造函数的this指向了子类实例。

借用构造函数继承的特点:1. 在子类中可以给父类传参。2. 可以继承父类的私有属性。

借用构造函数继承的缺点:只能继承父类的私有属性,不能继承父类的原型属性。

组合继承(可以传参,继承私有属性和原型属性,但造成冗余)

借用构造函数继承解决了子类不能给父类传参的问题,但是又带来了无法继承父类原型属性的问题。那如何让子类既能继承父类的原型属性又能继承父类的私有属性呢?

将原型继承和借用构造函数继承结合起来,就是组合继承。

// 父类构造函数
function Father(name) {
this.name = name;
} // 往父类原型上放一个say方法
Father.prototype.say = function() {
return 'i am your father';
} // 子类构造函数
function Child(name) {
// 借用构造函数继承
Father.call(this, name);
this.age = 16;
} // 原型继承
Child.prototype = new Father(); Child.prototype.sex = 'man'; var child = new Child('child');
// 调用父类的私有属性name
console.log(child.name); // child
// 调用父类的原型属性say
console.log(child.say()); // i am your father
// 调用子类的私有属性age
console.log(child.age); // 16
// 调用子类的原型属性sex
console.log(child.sex); // man

上述组合继承看似完美实现了继承,实则还存在有隐患。

那就是父类的name属性,既存在于Father类中,作为它的私有属性。又存在于Child类的prototype中,作为它的原型属性。

组合继承的实现:同时使用原型继承和借用构造函数继承。

组合继承的特点:1. 子类可以继承父类原型属性和私有属性。2. 子类可以给父类传参。

组合继承的缺点:对于父类的私有属性,子类继承时候同时存在于私有属性和原型属性中,造成了冗余。

寄生组合式继承(最佳实践)

解决组合式继承的冗余问题。

在使用借用构造函数继承之后,不用原型继承,而是用其他方法让子类只继承父类的原型属性而不继承父类的私有属性,就可以避免冗余了。

下面说明如何让子类只继承父类的原型属性而不继承父类的私有属性:

如果我们不给子类构造函数的prototype赋值为父类对象,而是赋值为一个只有父类原型属性而没有父类私有属性的对象,那么子类就不会继承到父类的私有属性,只会继承父类的原型属性了。如何生成这样一个对象呢?

// 父类构造函数
function Father(name) {
this.name = name;
} // 往父类原型上放一个say方法
Father.prototype.say = function() {
return 'i am your father';
} // 创建一个只拥有父类原型属性的实例对象
function getFatherProtoType(Father) {
function Func() {}
Func.prototype = Father.prototype;
return new Func();
} // 子类构造函数
function Child(name) {
// 借用构造函数继承
Father.call(this, name);
this.age = 16;
} Child.prototype = getFatherProtoType(Father); Child.prototype.sex = 'man'; var child = new Child('child');
// 调用父类的私有属性name
console.log(child.name); // child
// 调用父类的原型属性say
console.log(child.say()); // i am your father
// 调用子类的私有属性age
console.log(child.age); // 16
// 调用子类的原型属性sex
console.log(child.sex); // man

这样就实现了:1. 子类继承父类的私有属性和原型属性。2. 子类可以向父类传递参数。3. 继承后没有冗余属性。

寄生组合继承是js继承的最佳实践。

ES6之前,JS的继承的更多相关文章

  1. JS类继承常用方式发展史

    JS类继承常用方式发展史 涉及知识点 构造函数方式继承 1-继承单个对象 1.1 多步走初始版 1.2 多步走优化版 1.3 Object.create()方式 2-继承多个对象 2.1 遍历 Obj ...

  2. JS实现继承 JavaScript

    JS实现继承 JavaScript 定义一个父类: // 定义一个动物类 function Animal (name) { // 属性 this.name = name || 'Animal'; // ...

  3. 深入浅出js实现继承的7种方式

    给大家介绍7中js继承的方法 有些人认为JavaScript并不是真正的面向对象语言,在经典的面向对象语言中,您可能倾向于定义类对象,然后您可以简单地定义哪些类继承哪些类(参考C++ inherita ...

  4. JS对象继承篇

    JS对象继承篇 ECMAScript只支持实现继承,而且其实现继承主要是依靠原型链来实现的 原型链 其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法 function Person() ...

  5. js实现继承的5种方式 (笔记)

    js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...

  6. js实现继承的方式总结

    js实现继承的5种方式 以下 均为 ES5 的写法: js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承 ...

  7. 【09-23】js原型继承学习笔记

    js原型继承学习笔记 function funcA(){ this.a="prototype a"; } var b=new funcA(); b.a="object a ...

  8. js实现继承的两种方式

    这是面试时面试官会经常问到问题: js的继承方式大致可分为两种:对象冒充和原型方式: 一.先说对象冒充,又可分为3种:临时属性方式.call().apply(): 1.临时属性方式: 当构造对象son ...

  9. js实现继承

    js是门灵活的语言,实现一种功能往往有多种做法,ECMAScript没有明确的继承机制,而是通过模仿实现的,根据js语言的本身的特性,js实现继承有以下通用的几种方式1.使用对象冒充实现继承(该种实现 ...

  10. 浅谈JS的继承

    JS继承 继承是OO语言中最为人津津乐道的概念,许多OO语言都支持两种方式的继承:接口继承:实现继承. 接口继承:只继承方法签名. 实现继承:继承实际的方法. 由于ES里函数没有签名,所以在ES里面无 ...

随机推荐

  1. React技巧之表单提交获取input值

    正文从这开始~ 总览 在React中,通过表单提交获得input的值: 在state变量中存储输入控件的值. 在form表单上设置onSubmit属性. 在handleSubmit函数中访问输入控件的 ...

  2. android stdio开发抖音自动点赞案例

    最近做了一个安卓开发自动刷抖音. 点赞. 评论等等养号行为. 总结一下知识点和遇到的一些问题: 知识点: 1. 使用acessibility mode 对抖音自动化操作. android stdio中 ...

  3. Pytorch从0开始实现YOLO V3指南 part3——实现网络前向传播

    本节翻译自:https://blog.paperspace.com/how-to-implement-a-yolo-v3-object-detector-from-scratch-in-pytorch ...

  4. 【C++】学生管理系统

    [C++]学生管理系统 一道非常经典的C语言题目,用C++实现   题目如下: 输入功能:由键盘输入10个学生的学号.姓名.三科成绩,并计算出平均成绩和总成绩,然后将它存入文件stud.dat. 插入 ...

  5. super详解

    1.super和this的区别 super调用的是父类的属性或方法,this是调用当前类的属性或者方法.     (1)super和this关于属性的调用     (2)super和this关于方法的 ...

  6. java的类

    public class demo01 { public static void main(String[] args) { //类名可用中文也可用英文,但是不建议用中文 String 王者荣耀=&q ...

  7. ERROR .web.servlet.DispatcherServlet - Context initialization failed

    自己创建了一个SSM 项目,使用maven的tomcat7 运行报错 ERROR .web.servlet.DispatcherServlet - Context initialization fai ...

  8. SQLZOO练习三--SELECT within SELECT Tutorial

    This tutorial looks at how we can use SELECT statements within SELECT statements to perform more com ...

  9. ESXI启用本地登录和SSH服务连接功能,使用Xshell连接

    1.选中Troubleshoot Options进行SSH服务配置 2.开启本地登录功能 3.开启远程连接功能 4.本地登录修改SSH服务允许基于密码登录 默认无法用密码登录ssh服务,只支持基于ke ...

  10. C#/VB.NET: 将Word或Excel文档转化为Text

    Text文件只由纯文本内容组成,且没有格式,所以其大小比Word或Excel文件更小.除此之外,Text文件还具有跨平台性,几乎与所有应用程序都兼容.因此,在某些时候,我们可能需要将Word或Exce ...