博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
js继承有哪些方法
阅读量:4130 次
发布时间:2019-05-25

本文共 4044 字,大约阅读时间需要 13 分钟。

答案:

  • 原型继承

  • 构造继承

  • 组合继承(组合原型+构造)

  • 实例继承

  • 寄生组合继承

  • ES6 使用class extends继承

 

详细解析:

首先定义 父类Animal

//父类function Animal(name){    this.name = name;    this.sum = function() {        alert(this.name);    }}Animal.prototype.age = 10;  //父类原型属性

一、原型链继承:子类的原型等于父类的实例

instanceof 判断对象的具体类型(判断元素是否在另一个元素的原型链上),这里 dog1 继承了 父类Animal 的属性,返回true。

实例是子类的实例,也是父类的实例。

//原型链实现继承function Dog() {    this.name = "xu";}Dog.prototype = new Animal();  //关键语句,子类型的原型指向父类型的实例// 这里实例化一个 Animal 时, 实际上执行了两步// 1,新创建的对象复制了父类构造函数内的所有属性及方法// 2,并将原型 __proto__ 指向了父类的原型对象var dog1 = new Dog();console.log(dog1.age);  //10console.log(dog1 instanceof Animal);  //trueconsole.log(dog1 instanceof Dog);  //true

结果:

特点:

  1. 实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(父类新增原型方法/原型属性,子类都能访问的到)

缺点:

  1. 新实例无法向父类构造函数传参。
  2. 继承单一,无法实现多继承。
  3. 所有新实例都会共享父类实例的属性。(原型上的属性是共享的,一个实例修改了原型属性,另一个实例的原型属性也会被修改!)

 

二、构造函数继承:用 .call() 在子类的构造函数内部调用父类构造函数

实例并不是父类的实例,只是子类的实例,这里具体为 cat1 不是 父类Animal 的实例,因此返回false。

相对于原型链而言,借用构造函数有一个很大的优势,即可以在子类的构造函数中向父类构造函数传递参数。

//构造函数实现继承function Cat() {    //调用 Animal 构造函数    Animal.call(this, "animalType");  //关键语句,使用call()方法继承父类构造函数中的属性    //为了保证父类的构造函数不会重写子类的属性,需要在调用父类构造函数后,定义子类的属性    this.age = "5";  //子类属性}//子类实例var cat1 = new Cat();console.log(cat1.name);  //animalTypeconsole.log(cat1.age);  //5console.log(cat1 instanceof Animal);  //falseconsole.log(cat1 instanceof Cat);  //true

结果:

特点:

  1. 只继承了父类构造函数的属性,没有继承父类原型的属性。
  2. 解决了 原型继承 缺点1、2、3。不会造成原型属性共享的问题。
  3. 可以继承多个构造函数属性(call多个)。
  4. 在子实例中可向父实例传参。

缺点:

  1. 只能继承父类构造函数的属性/方法,不能继承原型属性/方法。
  2. 无法实现构造函数的复用。(每次用每次都要重新调用)
  3. 实例并不是父类的实例,只是子类的实例。
  4. 每个新实例都有父类构造函数的副本,影响性能,臃肿。

 

三、组合继承:结合了(原型链+构造)两种模式的优点,传参和复用

主要思想:使用原型继承使用对原型属性和方法的继承,通过构造函数继承来实现对实例属性的继承。这样既能通过在原型上定义方法实现函数复用,又能保证每个实例都有自己的属性。

通过调用父类构造,继承父类的属性并保留传参的优点,然后通过将父类实例作为子类原型,实现函数复用。

//组合继承function Cat(name) {	Animal.call(this, name);  //构造继承 ----第二次调用 父类Animal----}// ----第一次调用 父类Animal----Cat.prototype = new Animal();  //原型继承Cat.prototype.constructor = Cat;  //组合继承需要修复构造函数的指向var cat = new Cat("miao");console.log(cat.name);	//miao 继承了构造函数属性console.log(cat.age);	//10 继承了父类原型的属性console.log(cat instanceof Animal); //trueconsole.log(cat instanceof Cat); //true

结果:

特点:

  1. 可以继承实例属性/方法,也可以继承原型属性/方法。不存在引用属性共享问题,可传参,可复用。
  2. 每个新实例引入的构造函数属性是私有的。

缺点:

调用了两次父类构造函数(耗内存),生成了两份实例。子类的构造函数会代替原型上的那个父类构造函数。

 

四、实例继承:为父类实例添加新特性,作为子类实例返回

实例是父类的实例,不是子类的实例,这里具体为 cat1 不是 子类Cat 的实例,因此返回false

//实例继承核心:为父类实例添加新特性,作为子类实例返回function Cat(name) {    var instance = new Animal();    instance.name = 'cc';    return instance;}var cat = new Cat();console.log(cat.name);	//ccconsole.log(cat instanceof Animal);  //trueconsole.log(cat instanceof Cat);  //false

结果:

特点:

  1. 不限制调用方式,不管是new子类()还是子类(),返回的对象都具有相同的效果

缺点:

  1. 实例是父类的实例,不是子类的实例
  2. 不支持多继承

 

五、寄生组合继承

核心:在组合继承中,调用了两次父类构造函数,这里 通过寄生方式,砍掉父类的实例属性,这样,在调用两次父类的构造的时候,就不会初始化两次实例方法/属性,避免的组合继承的缺点。

 

主要思想:借用 构造函数 继承 属性 ,通过 原型链的混成形式 来继承 方法。

// 父类function SuperType (name) {  this.colors = ["red", "blue", "green"];  this.name = name; // 父类属性}SuperType.prototype.sayName = function () { // 父类原型方法  return this.name;};// 子类function SubType (name, subName) {  // 调用 SuperType 构造函数  SuperType.call(this, name); // ----第二次调用 SuperType,继承实例属性----  this.subName = subName;};// ----第一次调用 SuperType,继承原型属性----SubType.prototype = Object.create(SuperType.prototype)SubType.prototype.constructor = SubType; // 注意:增强对象let instance = new SubType('An', 'sisterAn')

 

六、ES6 使用 class extends 继承

//ES6 class extends 继承class Person{    constructor(name, age){ //constructor构造函数        this.name=name;        this.age=age;    }    show(){        console.log(this.name);        console.log(this.age);    }}class Worker extends Person{  //子类继承父类    constructor(name, age, job){        super(name, age);        this.job=job;    }    showJob(){        console.log(this.job);    }}let worker1 = new Worker('jia', 21, '班长');worker1.show();worker1.showJob();

结果:

通过class创建对象看起来就比较简洁,不用通过原型去实现继承。

在class的继承中,子类的_proto_属性表示构造函数的继承,指向父类,子类prototype属性的_proto_属性,表示方法的继承,总是指向父类的prototype属性

class调用必须通过new 关键字。

class中的static 属性:用于定义类中的静态方法和静态属性关键字。

该方式声明的方法与属性,只能通过类名调用,可被继承,并且定义方法的 this 指向类 而不是实例。

ES中的function 可以用call apply bind 的方式 来改变他的执行上下文,但是 class 不可以 。

转载地址:http://njuvi.baihongyu.com/

你可能感兴趣的文章
XML生成(三):JDOM生成
查看>>
Ubuntu Could not open lock file /var/lib/dpkg/lock - open (13:Permission denied)
查看>>
collect2: ld returned 1 exit status
查看>>
C#入门
查看>>
C#中ColorDialog需点两次确定才会退出的问题
查看>>
数据库
查看>>
nginx反代 499 502 bad gateway 和timeout
查看>>
linux虚拟机安装tar.gz版jdk步骤详解
查看>>
python实现100以内自然数之和,偶数之和
查看>>
python数字逆序输出及多个print输出在同一行
查看>>
苏宁产品经理面经
查看>>
百度产品经理群面
查看>>
去哪儿一面+平安科技二面+hr面+贝贝一面+二面产品面经
查看>>
element ui 弹窗在IE11中关闭时闪现问题修复
查看>>
vue 遍历对象并动态绑定在下拉列表中
查看>>
Vue动态生成el-checkbox点击无法选中的解决方法
查看>>
python __future__
查看>>
MySQL Tricks1
查看>>
python 变量作用域问题(经典坑)
查看>>
pytorch
查看>>