js继承的几种方式

发布于:2023-03-02 ⋅ 阅读:(147) ⋅ 点赞:(0)

1. 原型链继承

原型链继承:想要继承,就必须要提供父类(继承谁,提供继承的属性)

//父级
function Person(name) {   //给构造函数添加参数
    this.name = name;
    this.age = 10;
    this.sum = function (){
        console.log(this.name)
    }
}
//原型链继承
function Per() {

}
Per.prototype = new Person(); //主要 实现继承
var per1 = new Per();
console.log(per1.age);  //10

重点:让新实例的原型等于父类的实例 特点:1.实例可继承的属性有:实例的构造函数的属性,父类构造函数属性,父类原型的属性。(新实例不会继承父类实例的属性!) 缺点: 1>新实例无法向父类构造函数参数。 2>父子构造函数的原型对象之间有共享问题

2. 借用构造函数继承

使用call和apply借用其他构造函数的成员, 可以解决给父构造函数传递参数的问题, 但是获取不到父构造函数原型上的成员.也不存在共享问题

//父级
function Person(name) {   //给构造函数添加参数
    this.name = name;
    this.age = 10;
    this.sum = function (){
        console.log(this.name)
    }
}
//子构造函数
function Per(name) {
    //使用call借用Person的构造函数
    Person.call(this,name)
}
//测试是否有了Person的成员
var stn = new Per('我是');
stn.sum();   //   我是
console.log(stn.age)

重点:用.call()和.apply()将父类构造函数引入子类函数(在子类函数中做了父类函数的自执行(复制)) 缺点:1、只能继承父类构造函数的属性。    2、无法实现构造函数的复用。(每次用每次都要重新调用)    3、每个新实例都有父类构造函数的副本,臃肿。 特点:1、只继承了父类构造函数的属性,没有继承父类原型的属性。    2、解决了原型链继承缺点1、2、3。    3、可以继承多个构造函数属性(call多个)。    4、在子实例中可向父实例传参。

3. 组合继承

借用构造函数 + 原型式继承

//父级
function Person(name) {   //给构造函数添加参数
    this.name = name;
    this.age = 10;
    this.sum = function (){
        console.log(this.name)
    }
}
//创建子构造函数
function Per(name) {
    Person.call(this,name); //借用构造函数
}
Per.prototype = new Person() //继承原型链继承
var str = new Per('zhao');
console.log(str.name); //'zhao'  是继承了Per子构造函数的属性
console.log(str.age);  // 10   是继承了Person父类原型的属性

重点:结合了两种模式的优点,传参和复用 特点:1、可以继承父类原型上的属性,可以传参,可复用。    2、每个新实例引入的构造函数属性是私有的。 缺点:调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数

4. 原型链继承

//父级
function Person(name) {   //给构造函数添加参数
    this.name = name;
    this.age = 10;
    this.sum = function (){
        console.log(this.name)
    }
}
//设置父构建函数的原型
Person.prototype.fn = function (){
    console.log(this.age)
}
//构建子构造函数
function Per() {

}
//实现继承
var str = new Person(); //拿到父类的实例
console.log(str.age);  // 10
str.fn();    10

重点:用一个函数包装一个对象,然后返回这个函数的调用,这个函数就变成了个可以随意增添属性的实例或对象。object.create()就是这个原理。 特点:类似于复制一个对象,用函数来包装。 缺点:1、所有实例都会继承原型上的属性。    2、无法实现复用。(新实例属性都是后面添加的)

5. 寄生式继承

//父级
function Person(name) {   //给构造函数添加参数
   function fn(){}
   fn.prototype = name; //继承传入的参数
   return new fn();  //返回函数对象
}
var str = new Person();
//以上是原型式继承,给原型式继承在套一个壳子传递参数 
function Per(name) {
    var fn1 = Person(name);
    fn1.name = "zhao";
    return fn1
}
var fn3 = Per(str);
console.log(fn3.name); //返回str对象,继承了str的属性

重点:就是给原型式继承外面套了个壳子。 优点:没有创建自定义类型,因为只是套了个壳子返回对象(这个),这个函数顺理成章就成了创建的新对象。 缺点:没用到原型,无法复用

6. 寄生组合式继承

function Person(name){
    this.name = name;
    this.hobbies = ['a','b','v']
};
function student(name,age){
    Person.call(this,name);
    this.age = age;
}
//关键的三步 实现继承
// 使用F空函数当子类和父类的媒介 是为了防止修改子类的原型对象影响到父类的原型对象
let fn = function (){};
fn.prototype = Person.prototype;

student.prototype = new fn();
var fn1 = new student('zhao','24')
console.log(fn1)

组合继承最大的缺点是最调用两次父构造函数 一次是设置子类实例的原型的时候:

 student.prototype = new Person();

一次是在创建子类型实例的时候:

var fn = new student('zhao','24')

7. es6实现继承

class parents {
    constructor(){
        this.grandmather = 'rose';
        this.grandfather = 'jack';
    }
}

class children extends parents{
    constructor(mather,father){
    //super 关键字,它在这里表示父类的构造函数,用来新建父类的 this 对象。
        super();
        this.mather = mather;
        this.father = father;
    }
}

let child = new children('mama','baba');
console.log(child)
本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到