继承的多种实现方式及优缺点<前端学习笔记>

一、原型链的继承

实现

function Parent(){
  this.name = "ParentName";
  //引用类型
  this.actions = ['sing','jump','rap']
}
Parent.prototype.sas = "22"

function Child(){}

// Parent中this 一直指向Child的原型对象,共享了所有引用类型 
Child.prototype = new Parent();
//原型被修改,需要重新赋值constructor
Child.prototype.constructor = Child;

const c1 = new Child();

console.log(Child.prototype.__proto__) //{ sas: '22' }

缺点

1.父类存在引用类型,其中一个实如果改变了此变量,那么所有实例都会共享
2.无法传参给Parent

二、构造函数继承

实现

function Parent(name){
    this.name = name;
    //引用类型
    this.actions = ['sing','jump','rap'];
}

function Child(name){
    //使用call改变this,不存在访问同一个原型属性问题,解决引用类型的共享,都是每new一个就会产生多父类的this属性和方法 
    //改变Parent的this指向,将引用数据类型独立,并且可以传值
    Parent.call(this,name);
}

const c1 = new Child("c1");
const c2 = new Child("c2");
//向C1的actions中添加元素
c1.actions.push("basketball");
console.log(c1);//Child { name: 'c1', actions: [ 'sing', 'jump', 'rap', 'basketball' ] }
//c2不受影响
console.log(c2);//Child { name: 'c2', actions: [ 'sing', 'jump', 'rap' ] }

缺点

1.浪费内存(每new一个对象就会在父类this很多属性和方法)

三、组合继承

实现

//原型链继承 + 构造函数继承
function Parent(name,actions){
    this.name = name;
    this.actions = actions;
}
// 属性挂载到原型对象,减少生成次数
Parent.prototype.getName = function(){
    console.log(this.name,"调用了getName");
}

function Child(){
    // 修改了Parent 的this指向,引用类型不再共享
    Parent.apply(this,arguments);//第一次调用构造函数
}

// 继承原型对象 Parent this指向Child原型对象
Child.prototype = new Parent();//第二次调用构造函数  constructor被覆盖
Child.prototype.constructor = Child;

//1.实现传参
const c1 = new Child("c1",["eat","run"]);
c1.actions.push("gogo");
const c2 = new Child("c2",["sleep"]);
//2.引用类型相互独立
console.log(c1);//Child { name: 'c1', actions: [ 'eat', 'run', 'gogo' ] }
console.log(c2);//Child { name: 'c2', actions: [ 'sleep' ] }

//3.所有实例共享prototype,不占用内存
console.log(c1.getName === c2.getName);
c1.getName();//c1 调用了getName
c2.getName();//c2 调用了getName

缺点

1.调用了两次构造函数,生成了多余的属性,浪费不必要的内存(比构造函数少)

四、寄生组合式继承

实现

function Parent(name,actions){
  this.name = name;
  this.actions = actions;
}

Parent.prototype.getName = function(){
  console.log(this.name,"调用了getName");
}

function Child(){
  Parent.apply(this,arguments);
}

// Child.prototype = Parent.prototype; 
//替换的new 但是子原型一改会波及到父原型。 constructor被覆盖,是对象的引用关系
//所以不能直接赋值,需要桥梁
// Child.prototype = Object.create(Parent.prototype);
//手动实现Object.create 桥梁 

let TempFnction = function(){};
TempFnction.prototype = Parent.prototype;
// new返回一个新对象,不存在引用关系  Child.prototype 对象,new返回的是个对象不能直接用Child接收
Child.prototype = new TempFnction();
Child.prototype.constructor = Child;

//1.实现传参
const c1 = new Child("c1",["eat","run"]);
c1.actions.push("gogo");
const c2 = new Child("c2",["sleep"]);

//验证是否修改了父原型
Child.prototype.ap = function(){

}
console.log(Child.prototype);//Parent { constructor: [Function: Child], ap: [Function (anonymous)] }
console.log(Parent.prototype);//{ getName: [Function (anonymous)] }

//2.引用类型相互独立
console.log(c1);//Child { name: 'c1', actions: [ 'eat', 'run', 'gogo' ] }
console.log(c2);//Child { name: 'c2', act ions: [ 'sleep' ] }

//3.所有实例共享prototype,不占用内存
console.log(c1.getName === c2.getName);
c1.getName();//c1 调用了getName
c2.getName();//c2 调用了getName

五.Class实现继承

实现

// 父类
class People {
    constructor(name) {
        this.name = name;
        this.actions = ["sing"]
    }
    eat() {
        console.log(`${this.name} eat something`)
    }
}
 
// 子类继承父类 
// 如果需要用到父类的属性通过super可以直接拿到
class Teacher extends People {
    constructor(name,major) {
        // super直接拿类定义过的值来用
        super(name)
        this.major = major
    }
    teach() {
        console.log(`${this.name} 教授 ${this.major}`)
    }
}
// 可以传参
const zhangsan = new Teacher('张三',"化学")
const wanglaoshi = new Teacher('王老师', '语文')

zhangsan.eat();   // 张三 eat something
wanglaoshi.eat(); //王老师 eat something

//修改引用类型
zhangsan.actions.push("jump");
//并未共享
console.log(zhangsan);//Teacher { name: '张三', actions: [ 'sing', 'jump' ], major: '化学' }
console.log(wanglaoshi)//Teacher { name: '王老师', actions: [ 'sing' ], major: '语文' }

wanglaoshi.teach();  // 王老师 教授 语文
zhangsan.teach(); //张三 教授 化学
//不重新开辟空间
console.log(zhangsan.teach === wanglaoshi.teach);//true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值