一. 前言:

Hello,大家最近过得好吗,😃。函数继承是在JS里比较基础也是比较重要的一部分,而且也是面试中常常要问到的。下面带你快速了解JS中有哪几种是经常出现且必须掌握的继承方式。掌握下面的内容面试也差不多没问题啦~

当然,这需要一定的原型链基础,对原型链不熟悉的可以看我这篇文章👉:速识js原型链。

二.原型链继承:

原型链继承的要点在于父类的实例作为子类的原型。直接看下面这个例子:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name   " like "   this.nature[0]);
  };
  // 子函数 Jack
  function Jack() {}
  // 父类的实例作为子类的原型 (-------------------实现核心--------------------------)
  Jack.prototype = new Person();

现在我们创建两个Jack 的实例,测试看是否实现了继承Person:

      var jack1 = new Jack();
      var jack2 = new Jack();
      jack2.nature[0] = "sea";
      jack1.sayLove();
      jack2.sayLove();   
      console.log(jack1.nature);
      console.log(jack2.nature);  

看运行结果确实继承了,能执行sayLove方法。但有甚多缺点,创建Jack实例的时候传递不了参数name和age,而且不同实例间nature引用类型属性相互影响,一个改变那都改变:

在这里插入图片描述

三.借用构造函数继承(对象伪装):

核心在于“盗用构造函数”(constructor stealing)。在子类构造函数中调用父类构造函数。因为毕竟函数就是在特定上下文中执行代码的简单对象,所以可以使用apply()和call()方法以新创建的对象为上下文执行构造函数。它能解决原型链继承中传参数和引用类型属性冲突。还是直接看例子:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name   " like "   this.nature[0]);
  };
  // 子函数 Lucy
  function Lucy(name, age) {
  // 通过call把this指向Lucy,相当于拷贝了一份父函数 Person 里的内容(---------实现核心--------------)
        Person.call(this, name, age);
      }
  //给子函数原型上也定义一个方法
   Lucy.prototype.syaName = function () {
        console.log("My name is "   this.name);
      };

现在我们创建两个Lucy 的实例,测试看是否实现了继承Person:

      var lucy1 = new Lucy("lucy1", "20");
      var lucy2 = new Lucy("lucy2", "22");
      lucy2.nature[0] = "sea";
      console.log(lucy1.name);
      console.log(lucy1.nature);
      console.log(lucy2.nature);
      lucy1.syaName();
      lucy2.syaName();
      lucy1.sayLove();

结果看可以继承了,能传参数,引用类型属性也不互相影响,但是缺点显而易见,可以看到报错,无法使用父类的原型上的方法sayLove。

在这里插入图片描述

四.组合继承:

组合继承就是结合了原型链继承和借用构造函数继承两者的核心实现的一种继承方法,既能传递参数,引用类型属性也互不影响,同时子类也能获取得到父类的方法。这也是目前比较常用的继承方式。直接看例子:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name   " like "   this.nature[0]);
  };
  // 子函数Lisa
      function Lisa(name, age) {
// 通过call把this指向Lisa,相当于拷贝了一份父函数 Person 里的内容(------实现核心-----------)      
        Person.call(this, name, age);
      }
// 父类的实例作为子类的原型 (--------------实现核心-------------------)      
      Lisa.prototype = new Person();
  //小知识点,这里是让Lisa的constructor重新指向Lisa,不然因为Lisa的原型为Person实例,constructor会指向Person
      Lisa.prototype.constructor = Lisa;

现在我们创建两个Lisa 的实例,测试看是否实现了继承Person:

      var lisa1 = new Lisa("lisa1", "20");
      var lisa2 = new Lisa("lisa2", "21");
      lisa2.nature[0] = "sea";
      console.log(lisa1.name);
      console.log(lisa1.nature);
      console.log(lisa2.nature);
      lisa1.sayLove();
      lisa2.sayLove();

可以看到基本上实现了我们继承的功能。也修补了原型链和借用构造函数继承的缺点。但是呢,它还是有一个小缺点,就是可以看到在代码注释实现核心那,两次都调用了Person,那么Lisa原型上和实例上有了两份相同的属性,那就会多少有一些性能浪费。

在这里插入图片描述

五.寄生组合继承:

其实寄生组合继承和组合继承差不多的,就是多了一个解决组合继承上原型和实例产生两份相同属性的缺点。解决核心是我们既然只是想要子类原型赋值为父类原型,那没必要new一个父类实例。直接创造一个新对象,它值为父类的原型,再将它赋值给子类原型就行了。

其中用到Object.create(proto,[propertiesObject])这个方法创建一个新对象。相当于新对象的__proto__为其参数proto。当然Object.create可能低版本ie没有,所以下面也自定义封装了Object.create方法,当然只是简单封装。直接看例子:

 // 父函数 Person
  function Person(name, age) {
    // 定义一些属性
    this.name = name;
    this.age = age;
    this.nature = ["auroras", "wind", "moon"];
  }
 // 定义Person原型上的一个方法
  Person.prototype.sayLove = function () {
    console.log(this.name   " like "   this.nature[0]);
  };
  // 子函数 Andy
 function Andy(name, age) {
        Person.call(this, name, age);
      }
// 如果没有 Object.create()方法,简单封装下
      if (!Object.create) {
        Object.create = function (proto) {
          function Temp() {}
          Temp.prototype = proto;
          return new Temp();
        };
      }
// 调用Object.create方法,新建一对像,其__proto__为Person.prototype,并赋值给 Andy.prototype (-------实现核心----------)
      Andy.prototype = Object.create(Person.prototype);
  //修改constructor指向
      Andy.prototype.constructor = Andy;

现在我们创建两个Andy的实例,测试看是否实现了继承Person:

      console.log(Andy.prototype.__proto__ === Person.prototype);
      var andy1 = new Andy("andy1", "20");
      var andy2 = new Andy("andy2", "21");
      andy2.nature[0] = "sea";
      console.log(andy1.name);
      console.log(andy1.nature);
      console.log(andy2.nature);
      andy1.sayLove();
      andy2.sayLove();

完美运行:

在这里插入图片描述

六.class继承:

ES6出了class语法糖之后,就可以通过class定义类并实现类的继承。直接看例子:

//定义一个父类 Animal
  class Animal {
   //这里constructor指向类本身,跟es5行为一样的
    constructor(name) {
      this.name = name;
    }
    likeEat() {
      console.log(this.name   " like eat "   this.food);
    }
  }
//定义一个子类 Dog ,通过 extends 继承父类Animal
  class Dog extends Animal {   
    constructor(name, food) {
      //通过super(属性名)继承父类属性
     super(name);
     this.food = food;
    }
    likeEat() {
     //通过super. 父类方法 实现继承父类方法
      super.likeEat();
    }
  }

new一个Dog实例,测试看看,Dog是否继承了Animal:

  var jinmao = new Dog("jinmao", "bone");
  console.log(jinmao.name);
  jinmao.likeEat();

可以看到完美实现了:

在这里插入图片描述

七.总结:

方法 优点 缺点
原型链继承 能继承父原型上属性方法等等… 无法传参、引用类型属性冲突等等…
借用构造函数继承 可以传参,引用类型属性不冲突等等… 无法继承父原型上方法等等…
组合继承 有上面两种的优点,并解决其缺点 调用两次父实例产生两份相同属性等等…
寄生组合继承 有上面三种优点,并解决其缺点 可能不太直观等等…
class继承 es6新语法,简洁直观等等… 低版本ie不支持es6等等…

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注Devmax的更多内容!

一篇文章教你JS函数继承的更多相关文章

  1. html5 拖拽及用 js 实现拖拽功能的示例代码

    这篇文章主要介绍了html5 拖拽及用 js 实现拖拽,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  2. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. swift皮筋弹动发射飞机ios源码

    这是一个款采用swift实现的皮筋弹动发射飞机游戏源码,游戏源码比较详细,大家可以研究学习一下吧。

  4. Swift与Js通过WebView交互

    开发环境:Swfit2.3XCode8.2基础概念jscontext,jscontext是代表JS的执行环境,通过-evaluateScript:方法就可以执行一JS代码JSValue,JSValue封装了JS与ObjC中的对应的类型,以及调用JS的API等JSExport,JSExport是一个协议,遵守此协议,就可以定义我们自己的协议,在协议中声明的API都会在JS中暴露出来,才能调用Swif

  5. JSCore swift

    如果双方相互引用,会造成循环引用,而导致内存泄露。以上是Jscore的基本使用,比较简单

  6. Swift WKWebView的js调用swift

    最近项目需求,需要用到JavaScriptCore和WebKit,但是网上的资源有限,而且比较杂,都是一个博客复制另外一个博客,都没有去实际敲代码验证,下面给大家分享一下我的学习过程。

  7. Swift WKWebView的swift调用js

    不多说,直接上代码:在html里面要添加的的代码,显示swift传过去的参数:这样就实现了swift给js传参数和调用!

  8. 在 Swift 專案中使用 Javascript:編寫一個將 Markdown 轉為 HTML 的編輯器

    你有強烈的好奇心,希望在你的iOS專案中使用JavaScript。jscontext中的所有值都是JSValue對象,JSValue類用於表示任意類型的JavaScript值。因此,我們既需要寫Swift代碼也要寫JavaScript代碼。此外,我們還會在JavaScript中按照這個類的定義來創建一個對象并對其屬性進行賦值。從Swift中呼叫JavaScript就如介紹中所言,JavaScriptCore中最主要的角色就是jscontext類。一個jscontext對象是位於JavaScript環境和本

  9. swift - WKWebView JS 交互

    本文介绍WKWebView怎么与js交互,至于怎么用WKWebView这里就不介绍了HTML代码APP调JS代码结果JS给APP传参数首先注册你需要监听的js方法名2.继承WKScriptMessageHandler并重写userContentController方法,在该方法里接收JS传来的参数3.结果

  10. swift 开发UIWebView跟JS的交互

    前言作为小白的我,才开始入门IOS,选择了swift来进行入门学习,学习做着公司一个简单的小小项目,该项目需要进行跟H5进行交互,然后我就开始研究了UIWebView的使用,其实基本原理跟Android的一样,因为我是Android开发的,所以就顺水推舟了。))//这里设置你需要加载的地址}overridefuncdidReceiveMemoryWarning(){super.didReceiveMemoryWarning()//disposeofanyresourcesthatcanberecreate

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部