JS实现继承的方式原生版

下一篇:JS实现继承的方式ES6版

实现继承的方式

在这里插入图片描述

类的定义

function People(name){
  //属性
  this.name  = name || Annie
  //实例方法
  this.sleep=function(){
    console.log(this.name + '正在睡觉')
  }
}
//原型方法
People.prototype.eat = function(food){
  console.log(this.name + '正在吃:' + food);
}

1 原型链继承:将子类构造函数的原型指向父类的一个实例。

function Parent() {
    this.name = "Parent";
}
Parent.prototype.say = function() {
    return this.name;
}
function Child() {
    this.childName = "Child";
}

Child.prototype = new Parent();

const child1 = new Child()
console.log(child1.say())

此时子类的constructor指向了父类。
优点:
实现简单。
缺点:
创建子类实例的时候不能向父类传参。
父类的引用数据类型属性被子类实例修改后,所有的子类实例上的该属性值也会跟着被修改。

2 借用构造函数继承:在子类构造函数里调用父类构造函数并传参,使用 call 改变 this 指向。

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

function Child(name, age) {
    father.call(this, name, age)
}

const child1 = new Child('name', 12)

优点:
解决了子类实例共享父类引用属性的问题。
创建子类实例时,可以向父类构造函数传参。
可以实现多继承(call多个)。
缺点:
无法继承父类原型中的方法。(除非父类的方法写入构造函数中,每次创建实例都会创建一遍方法,函数复用就无从谈起了)

3 组合继承:将原型链和借用构造函数的技术结合到一起。

背后思想是使用原型链实现对方法的继承,通过借用构造函数实现对实例属性的继承。这样,既能够保证能够通过原型定义的方法实现函数复用,又能够保证每个实例有自己的属性。

function Parent(name, age) {
    this.name = name;
    this.age = age;
    this.colors = ['red', 'green']
}
Parent.prototype.say = function() {
    return this.name;
}
function Child(name, age, grade) {
    Parent.call(this, name, age);// 创建子类实例时会执行一次
    this.grade = grade;
}

Child.prototype = new Parent(); // 指定子类原型会执行一次
Child.prototype.constructor = Child;// 校正构造函数

优点:
组合继承既具有原型链继承能够复用函数的特性,又有借用构造函数方式能够保证每个子类实例能够拥有自己的属性以及向超类传参的特性。
缺点:
在创建子类时会调用两次超类的构造函数。

4 原型式继承:更像是拷贝,借助原型可以基于已有的对象创建新对象。

let person = {
     name:"haha",
     family:['papa','mama']
}
let child = Object.create(person);

ECMAScript5通过新增Object.create()方法规范化了原型式继承,这个方法接收两个参数:一个用作新对象原型的对象和为新对象定义属性的对象
Object.create()手写。先创建了一个空的临时性构造函数,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。本质上object()就是完成了一次浅复制操作:

function create() {
    function f(){}
    f.prototype = obj;
    return new f();
}

缺点:
父类引用属性会被所有实例共享,因为是用整个父类对象来充当了子类原型对象。
无法传递参数。

5 寄生式继承:与原型式继承紧密相关的一种思路。

创建一个仅用于封装继承函数过程的函数,该函数在内部以某种方式来增强对象,最后返回对象。

let parent = {
     name:"haha",
     family:['papa','mama']
}

function createChild(parent) {
    let child = Object.create(parent);
    // 增强的方法
    child.functionXX = function(){xx}
    return child;
}

let child = createChild(parent);

缺点:和上面原型式继承一样。(就是给原型式继承套上一层函数而已,让原型式看起开更像继承,并没有解决根本问题)

6 寄生式组合继承

以上的方式多少都会有点缺陷,要达到完美继承就需要在组合式继承(伪经典继承)身上进行改造,但是要达到能传参,并且还要实现多继承的目的,那么在子类内部调用父类构造函数Father.call()这一步就不能动。
只能考虑Child.prototype = new Father 这一步,最终需要达到目的:Child.Prototype.__ proto __ = Father.prototype(子类的原型指向父类的原型, 解决父类调用两次的缺陷)----->(也就是一个对象继承另一个对象,上面的寄生式和原型式继承方式),另外最后还是需要将子类实例的constructor指回子类。

//1. 父类 实例属性放在构造函数中
function Parent(name, age) {
    this.name = name
    this.age = age
    this.hobby = ['a', 'b', 'c']
}
// 父类方法放在原型上实现复用
Parent.prototype.sayName = function () {
    console.log(this.name)
}
//2. 子类
function Child(name, age) {
    Parent.call(this, name, age) // 调用父类的构造函数 (继承父类的属性)
    this.a = 1
}

// 创建父类的原型副本,改变子类的原型,同时纠正构造函数
function inherit(subClass, superClass) {
    var parent = Object.create(superClass.prototype);
    parent.constructor = subClass;
    subClass.prototype = parent;
}

inherit(Child, Parent);

完美实现了函数复用,传参,实例之间不会相互影响,多继承

参考:
https://juejin.cn/post/6844904161071333384
https://juejin.cn/post/7019185008527015949
https://juejin.cn/post/7080795936439402504

  • 25
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
原生 JavaScript 中,可以通过构造函数和原型链来实现面向对象继承。具体实现方式如下: 1. 构造函数继承 构造函数继承是通过在子类构造函数中调用父类构造函数来实现的。这种方式的缺点是无法继承父类原型上的方法和属性。 ```javascript function Parent(name) { this.name = name; } function Child(name, age) { Parent.call(this, name); this.age = age; } var child = new Child('Tom', 18); console.log(child.name); // Tom console.log(child.age); // 18 ``` 2. 原型链继承 原型链继承是通过将子类的原型指向父类的实例来实现的。这种方式的缺点是所有子类实例共享父类实例上的属性和方法。 ```javascript function Parent() { this.name = 'parent'; } Parent.prototype.sayHello = function() { console.log('Hello'); }; function Child() {} Child.prototype = new Parent(); var child1 = new Child(); var child2 = new Child(); console.log(child1.name); // parent console.log(child2.name); // parent child1.sayHello(); // Hello child2.sayHello(); // Hello ``` 3. 组合继承 组合继承是将构造函数继承和原型链继承结合起来使用的一种方式。这种方式既可以继承父类实例上的属性和方法,也可以继承父类原型上的属性和方法。 ```javascript function Parent(name) { this.name = name; } Parent.prototype.sayHello = function() { console.log('Hello'); }; function Child(name, age) { Parent.call(this, name); this.age = age; } Child.prototype = new Parent(); Child.prototype.constructor = Child; var child = new Child('Tom', 18); console.log(child.name); // Tom console.log(child.age); // 18 child.sayHello(); // Hello ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值