js继承有哪些方法

答案:

  • 原型继承

  • 构造继承

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

  • 实例继承

  • 寄生组合继承

  • 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);  //10
console.log(dog1 instanceof Animal);  //true
console.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);  //animalType
console.log(cat1.age);  //5
console.log(cat1 instanceof Animal);  //false
console.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); //true
console.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);	//cc
console.log(cat instanceof Animal);  //true
console.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 不可以 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值