js继承的方法和实现原理

js继承的方法和实现原理

ES6之前并没有专门用于继承的关键字。ES6之后有了Classextends

​ 实现继承首先需要一个父类;(继承谁,提供继承的属性)

//父类
function Person(name,age){
    this.name = name;
    this.age = age;
}

1.原型链继承

​ 将子类的原型对象 修改为 父类的实例对象。(让新实例的原型等于父类的实例)

Son.prototype = new Father();//重要
//父类
function Person(name,age){
    this.name = name;
    this.age = age;
}

//来个子类
function Teacher(jobTitle,pay){
    this.jobTitle = jobTitle;
    this.pay = pay;
} 

//实例化一个Person对象,将对象的地址赋值给Teacher的prototype属性。(实现继承)
//【注意】Teacher.prototype原来指向的对象就没有了,指向新的Person实例对象。
Teacher.prototype = new Person("马老师",30);

//构造实例
var t1 = new Teacher("体育",3000);

console.log(t1.name)

【缺点】:

​ 1.对复杂数据类型(引用数据类型)的修改会出现误差

​ 2.继承来的属性的值都是统一的。

2.构造函数继承

​ 在子类的构造函数中,普通方法调用父类的构造函数(复制父类的实例属性给子类),需要使用call或者apply来修改,构造函数的this指向

function Son(param1,param2){
      Father.call(this,param1,param2);
    }
//父类
function Person(name,age){
    this.name = name;
    this.age = age;
    this.eat = function() {
        console.log("干饭人干饭魂,干饭都得用大盆");
    }
}

//来个子类
function Teacher(name,age,pay){
    Person.call(this,name,age);
    this.pay = pay;
} 

//构造实例
var t1 = new Teacher("马老师",40,3000);
var t2 = new Teacher("张老师",25,10000);

console.log(t1.eat == t2.eat);//false  两个不同的函数不相等

【缺点】:

​ 1.继承来的方法只能定义在构造函数中,不能定义在父类的原型对象上

​ 2.继承来的函数无法复用,占用内存比较大。

3.组合继承

​ 结合了原型链继承和借用构造函数继承两者的优点;

​ 1.在子类的构造函数中借用父类的构造函数 father.call(this);

​ 2.将父类的方法定义在父类的原型对象上

​ 3.将子类的原型对象指向 父类的实例对象

​ 4.修正constructor属性

//父类
function Person(name, age) {
    this.name = name;
    this.age = age;
    this.emotion = ['喜', '怒', '哀', '乐']
}

//将父类的方法定义在父类的原型对象上
Person.prototype.eat = function() {
    console.log("干饭人干饭魂,干饭都得用大盆");
}

//来个子类
function Teacher(name, age, pay) {
    //将子类的构造函数中借用父类的构造函数
    Person.call(this, name, age)
    this.pay = pay;
}

//将子类的原型对象指向 父类的实例对象
Teacher.prototype = new Person();

//Teacher的原型对象已经被修改为Person的实例对象。Person的实例对象是没有construtor属性的,所以下面这个代码会输出false
console.log(Teacher.prototype.constructor == Teacher); //false 

//修正Teacher的原型对象上constructor属性的指向

Teacher.prototype.constructor = Teacher;

var t1 = new Teacher("王老师", 30, 5000);

console.log(t1.name); //可以继承父类的属性

t1.eat(); //可以继承 父类原型对象上的方法。

t1.emotion.push("愁");

console.log(t1.emotion);

var t2 = new Teacher("周老师", 35, 7000);

console.log(t2.emotion); //解决了 原型链继承中 对复杂数据类型修改出现误差的情况

console.log(t1); // name  age emotion pay 在t1这个实例对象上都有。

实际上是借用了构造函数,以覆盖的方式,解决了在原型链继承中原型的引用类型属性共享在所有实例中的问题。

【缺点】:

​ 调用了两次父类构造函数(耗内存),子类的构造函数会代替原型上的那个父类构造函数

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值