继承的概念

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

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

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

打个比方:

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

小明,就是一个具体的对象,他是人类,因此他拥有人类的共同属性和行为(有手有脚有嘴巴+会说话),除此之外,他还拥有一些独特的个性化的属性和行为,比如说他喜欢唱跳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. python采集一下美团外卖数据~~

    所需知识点(https://jq.qq.com/?_wv=1027&k=Ap5XvyNN) 1.动态数据抓包演示2.json数据解析3.requests模块的使用4.保存csv 安装命令:re ...

  2. 6 分钟看完 BGP 协议。

    上一篇文章见 万字长文爆肝路由协议! 上面我们聊 RIP .OSPF 协议都是基于 AS 即自治系统内的协议,可以把它们认为是域内路由协议:而下面我们要聊的就是 AS 之间的协议了,这也叫做域间路由协 ...

  3. Static、Final关键字详解

    1.Static 详情见下面代码讲解 点击查看代码 package com.Tang.oop.demo07; public class Student { private static int age ...

  4. APISpace 月出月落和月相API接口 免费好用

     月出和月落的位置,正如地球围绕太阳变化时产生的日出和日落一样,但是也和月相有关.一天中月亮升起的时间取决于它的月相.当你记得月相取决于太阳,月亮和地球的相对位置应该是明显的.月相是指从地球上看月球直 ...

  5. React中useEffect的简单使用

    学习hooks 在 React 的世界中, 组件有函数组件和类组件 UI 组件我们可以使用函数,用函数组件来展示 UI. 而对于容器组件,函数组件就显得无能为力. 我们依赖于类组件来获取数据,处理数据 ...

  6. linux系统中Nginx+FFmPeg+vlc实现网页视频播放配置过程

    linux系统中Nginx+FFmPeg实现网页监控视频播放配置过程 1.安装好的nginx上添加模块nginx-http-fiv-module-master 此模块是rtmp模块的升级版,有它所有的 ...

  7. flex 我所理解不够深刻的内容

    1.align-items属性   父元素 align-items属性定义项目在交叉轴上如何对齐. flex-start:交叉轴的起点对齐. flex-end:交叉轴的终点对齐. center:交叉轴 ...

  8. 清北学堂 2020 国庆J2考前综合强化 Day5

    目录 1. 题目 T1 a 题目描述 Sol T2 b 题目描述 Sol T3 c 题目描述 Sol T4 d 题目描述 Sol 2. 算法 - 贪心 & 数学 1. 贪心 2. 数学 2.1 ...

  9. 在阿里云Centos7.6上面部署基于Redis的分布式爬虫Scrapy-Redis

    原文转载自「刘悦的技术博客」https://v3u.cn/a_id_83 Scrapy是一个比较好用的Python爬虫框架,你只需要编写几个组件就可以实现网页数据的爬取.但是当我们要爬取的页面非常多的 ...

  10. Odoo 14 升级模块后为什么template不生效?

    # 升级模块后为什么template不生效? # 直接原因是因为你在record标签的父级data标签标签中设置了noupdate为true.这就导致你后面无论你怎么修改data下面的子标签内容,都不 ...