js继承总共分成5种,包括构造函数式继承、原型链式继承、组合式继承、寄生式继承和寄生组合式继承。

构造函数式继承

首先来看第一种,构造函数式继承,顾名思义,也就是利用函数去实现继承;构造函数继承,使用call和apply两个方法可以实现改变方法中的this

// 父类构造函数
function Parent(color) {
this.color = color;
this.print = function() {
console.log(this.color);
}
}

现在要编写一个子类函数来继承这个父类,如下:

// 子类构造函数
function Son(color) {
Parent.call(this, color);
  • 优点:所有的基本属性独立,不会被其他实例所影响;
  • 缺点:所有希望共享的方法和属性也独立了,没有办法通过修改父类某一处来达到所有子实例同时更新的效果;同时,每次创建子类都会调用父类构造函数一次,所以每个子实例都拷贝了一份父类函数的内容,如果父类很大的话会影响性能;

原型链继承

function Parent() {
this.color = 'red';
this.print = function() {
console.log(this.color);
}
}
function Son() {
}

我们有一个父类和一个空的子类;

Son.prototype = new Parent();
Son.prototype.constructor = Son;

接着我们把子函数的原型属性赋值给了父函数的实例;

var son1 = new Son();
son1.print(); // red

最后新建子类实例,调用父类的方法,成功拿到父类的color和print属性方法;

我们重点来分析一下下面两行代码:

Son.prototype = new Parent();
Son.prototype.constructor = Son;

这段代码中,子函数的原型赋给了父函数的实例,我们知道prototype是函数中的一个属性,js的一个特性就是:如果一个对象某个属性找不到,会沿着它的原型往上去寻找,直到原型链的最后才会停止寻找。

回到代码,我们看到最后实例son成功调用了Print方法,输出了color属性,这是因为son从函数Son的prototype属性上面去找到的,也就是从new Parent这个对象里面找到的;

这种方式也不是真正的继承,因为所有的子实例的属性和方法,都在父类同一个实例上了,所以一旦某一个子实例修改了其中的方法,其他所有的子实例都会被影响,来看下代码:

function Flower() {
this.colors = ['黄色', '红色'];
this.print = function () {
console.log(this.colors)
}
}
​
function Rose() {}
Rose.prototype = new Flower();
Rose.prototype.constructor = Rose;
​
var r1 = new Rose();
var r2 = new Rose();
​
console.log(r1.print()); // [ '黄色', '红色' ]
console.log(r1.print()); // [ '黄色', '红色' ]
​
r1.colors.push('紫色');
​
console.log(r1.print()); // [ '黄色', '红色', '紫色' ]
console.log(r2.print()); // [ '黄色', '红色', '紫色' ]

还是刚才的例子,这次Rose子类选择了原型链继承,所以,子实例r1修改了colors之后,r2实例的colors也被改动了,这就是原型链继承不好的地方。

来总结下原型链继承的优缺点:

  • 优点:很好的实现了方法的共享;
  • 缺点:正是因为什么都共享了,所以导致一切的属性都是共享的,只要某一个实例进行修改,那么所有的属性都会变化;

组合式继承

​function Parent(color) {
this.color = color;
}
Parent.prototype.print = function() {
console.log(this.color);
}
function Son(color) {
Parent.call(this, color);
}
Son.prototype = new Parent();
Son.prototype.constructor = Son;
​
var son1 = new Son('red');
son1.print(); // red
​
var son2 = new Son('blue');
son2.print(); // blue

上面代码中,在Son子类中,使用了Parent.call来调用父类构造函数,同时又将Son.prototype赋给了父类实例;为什么要这样做呢?为什么这样就能解决上面两种继承的问题呢?
我们接着分析一下,使用Parent.call调用了父类构造函数之后,那么,以后所有通过new Son创建出来的实例,就单独拷贝了一份父类构造函数里面定义的属性和方法,这是前面构造函数继承所提到的一样的原理;

然后,再把子类原型prototype赋值给父类的实例,这样,所有子类的实例对象就可以共享父类原型上定义的所有属性和方法。这也不难理解,因为子实例会沿着原型链去找到父类函数的原型。

因此,只要我们定义父类函数的时候,将私有属性和方法放在构造函数里面,将共享属性和方法放在原型上,就能让子类使用了。

以上就是组合式继承,它很好的融合了构造函数继承和原型链继承,发挥两者的优势之处,因此,它算是真正意义上的继承方式。

javaScript继承的几种实现方式?的更多相关文章

  1. js(javascript) 继承的5种实现方式

    详见:http://blog.yemou.net/article/query/info/tytfjhfascvhzxcyt240 js继承有5种实现方式:1.继承第一种方式:对象冒充  functio ...

  2. javascript继承有5种实现方式

    1.对象冒充 function Parent(username){ this.username = username; this.hello = function(){ alert(this.user ...

  3. JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)

    JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...

  4. 面向面试编程——javascript对象的几种创建方式

    javascript对象的几种创建方式 总共有以下几个模式: 1.工厂模式 2.构造函数模式 3.原型模式 4.混合构造函数和原型模式 5.动态原型模式 6.寄生构造函数模式 7.稳妥构造函数模式 1 ...

  5. JavaScript脚本的两种放置方式

    JavaScript脚本的两种放置方式 1在body里用 script标签引用 2 直接写在<script></script>标签之中

  6. JavaScript继承的几种实现

    0 什么是继承 继承就是获得存在对象已有的属性和方法的一种方式. [2019.4.26 更新]今日又重新学习了一下JS的继承,在这里整理一下以前的笔记并补充一些新的感悟. 1 JS中继承的几种实现方法 ...

  7. javascript继承的三种模式

    javascript继承一般有三种模式:组合继承,原型式继承和寄生式继承: 1组合继承:javascript最为广泛的继承方式通过原型链实现对原型属性和方法的继承,通过构造函数实现对实例属性的继承,同 ...

  8. JavaScript 函数的两种声明方式

    1.函数声明的方式 JavaScript声明函数有两种选择:函数声明法,表达式定义法. 函数声明法 function sum (num1 ,num2){ return num1+num2 } 表达式定 ...

  9. javascript中对象两种创建方式

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

随机推荐

  1. 早安打工人! 来把你的.NET程序模块化吧

    嗨朋友们,大家好! 还记得我是谁吗? 对了! 我就是 .NET 打工人 玩双截棍的熊猫 今天呐,我特别要向 写框架 的朋友们,想要写框架 ** 的朋友们,已经有框架** 的朋友问声好! 为什么呢?因为 ...

  2. nginx介绍及常用功能

    什么是nginx nginx跟Apache一样,是一个web服务器(网站服务器),通过HTTP协议提供各种网络服务. Apache:重量级的,不支持高并发的服务器.在Apache上运行数以万计的并发访 ...

  3. 【CF375D】Trees and Queries——树上启发式合并

    (题面不是来自Luogu) 题目描述 有一个大小为n且以1为根的树,树上每个点都有对应的颜色ci.现给出m次询问v, k,问以v为根的子树中有多少种颜色至少出现了k次. 输入格式 第一行两个数n,m表 ...

  4. 【mq读书笔记】消息过滤机制

    mq支持表达式过滤和类过滤两种模式,其中表达式又分为TAG和SQL92.类过滤模式允许提交一个过滤类到FilterServer,消息消费者从FilterServer拉取消息,消息经过FilterSer ...

  5. 2020.11最新JAVA环境安装配置

    Windows10下java环境配置 更新:2020年11月25日 电脑环境: windows10 64位 一.下载jdk 首先到Oracle网站下载对应操作系统的jdk安装包. https://ww ...

  6. Java Stream 源码分析

    前言 Java 8 的 Stream 使得代码更加简洁易懂,本篇文章深入分析 Java Stream 的工作原理,并探讨 Steam 的性能问题. Java 8 集合中的 Stream 相当于高级版的 ...

  7. DRF使用Serializer来进行序列化和反序列化操作

    在serlizers中添加 # -*- coding: utf-8 -*- from rest_framework import serializers from .models import * c ...

  8. day6(celery原理与组件)

    1.Celery介绍 1.1 celery应用举例 Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理,如果你的业务场景中需要用到异步任务,就可以考 ...

  9. PyQt(Python+Qt)学习随笔:Qt Designer中toolBar的movable属性

    1.概述 movable属性用来确认toolBar是否可以移动,如果设置为可移动,则toolBar可以在主窗口范围内拖拽移动. 2.访问方法 通过isMovable().setMovable(bool ...

  10. 使用 webpack 手动搭建 vue 项目

    webpack 是一个前端工程化打包工具,对于前端工程师来说 webpack 是一项十分重要的技能.下面我们就通过搭建一个 vue 项目来学习使用 webpack 主要环境: node v14.15. ...