JavaScript中常见的七种继承及实现

当需要创建新的对象时,继承是一个必须考虑的问题。JavaScript中的继承方式花样繁多,以下是常见的7种继承方式。

1.原型链继承

将父类的实例作为子类的原型,实现继承,示例代码如下:

function Parent() {
    this.name = 'parent';
}
Parent.prototype.getName = function() {
    return this.name;
};
function Child() {
    this.age=20;
}
Child.prototype=new Parent();
Child.prototype.getAge = function() {
    return this.age;
};

var child = new Child();
console.log(child.getName()); // parent
console.log(child.getAge()); // 20

缺点:原型链继承存在共享父类属性的缺点,对父类属性的修改会影响到所有子类实例。同时,无法向父类构造函数传参。

2.借用构造函数继承

在子类的构造函数中调用父类的构造函数,通过call和apply方法,在子类实例对象上执行构造函数中的代码,从而实现继承。示例如下:

function Parent(name) {
    this.name = name;
    this.getName = function() {
        return this.name;
    };
}
function Child(name, age) {
    // 在子类构造函数中使用apply调用父类构造函数,将父类的name变量绑定到实例对象上
    Parent.apply(this, [name]);
    this.age = age;
    this.getAge = function() {
        return this.age;
    };
}

var child = new Child('lucifer', 20);
console.log(child.getName()); // lucifer
console.log(child.getAge()); // 20

优点:借用构造函数继承解决了共享父类属性的问题,同时可以向父类构造函数传递参数。

缺点:每个子类对象都只能访问它自己的属性和方法,不能共享父类的原型中定义的属性和方法。

3.组合继承

将原型链继承和借用构造函数继承组合起来。即通过借用构造函数来继承父类的属性和方法,在子类原型中定义方法实现对父类原型的继承,即同时继承属性和方法。不过,这样做也会存在一些缺点,比如调用了两次父类构造函数。示例代码如下:

function Parent(name) {
    this.name = name;
    this.colors = ['red', 'green', 'blue'];
}
Parent.prototype.getName = function() {
    return this.name;
};

function Child(name, age) {
    Parent.call(this, name);
    this.age = age;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;
Child.prototype.getAge = function() {
    return this.age;
};

var child1 = new Child('lucifer', 20);
child1.colors.push('white');
console.log(child1.getName()); // lucifer
console.log(child1.getAge()); // 20
console.log(child1.colors); // [ 'red', 'green', 'blue', 'white' ]

var child2 = new Child('zhenyuan', 18);
console.log(child2.getName()); // zhenyuan
console.log(child2.getAge()); // 18
console.log(child2.colors); // [ 'red', 'green', 'blue' ]

优点:既继承了父类原型上的方法,又继承了父类构造函数上的属性,属性不会再对象之间共享,可以传参。

缺点:其缺点是调用了两次父类构造函数,生成了两份实例。

4.原型式继承

通过指定一个对象作为新对象的原型,基于已有的对象创建一个新的对象。比实现继承的第一种方式(原型链继承)更加灵活。示例代码如下:

function createObj(o) {
    function F(){}
    F.prototype=o;
    return new F();
}

var person={
    name:'lucifer',
    colors:['red','green','blue']
}
var child=createObj(person);
child.colors.push('white');

console.log(child.name) // lucifer
console.log(child.colors) // [ 'red', 'green', 'blue', 'white' ]

缺点:浅拷贝,存在引用类型共享的问题。

5.寄生式继承

与原型式继承类似,但略微不同。基本思路是创建一个仅用于封装继承过程的临时构造函数,最后返回这个构造函数。示例代码如下:

function inheritObj(obj) {
    var clone = Object.create(obj);
    clone.sayName = function() {
        console.log('hi');
    };
    return clone;
}
var person = {
    name: 'lucifer',
    colors: ['red', 'green', 'blue']
};
var child = inheritObj(person);

优点:在原型式继承的基础上,添加了新的属性和方法,相对原型式继承更加灵活。

缺点:无法复用父类的方法,与组合继承类似存在两份构造函数和原型。

6.寄生组合式继承

通过借用构造函数来继承属性,通过原型链的混合形式来继承方法。这种继承方式比较经典,是继承的最优解。示例代码如下:

function Parent(name) {
    this.name = name;
    this.colors = ['red', 'green', 'blue'];
}
Parent.prototype.getName = function() {
    return this.name;
};

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

Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;
Child.prototype.getAge = function() {
    return this.age;
};

var child1 = new Child('lucifer', 20);
child1.colors.push('white');
console.log(child1.getName()); // lucifer
console.log(child1.getAge()); // 20
console.log(child1.colors); // [ 'red', 'green', 'blue', 'white' ]

var child2 = new Child('zhenyuan', 18);
console.log(child2.getName()); // zhenyuan
console.log(child2.getAge()); // 18
console.log(child2.colors); // [ 'red', 'green', 'blue' ]

优点:不存在调用父类构造函数两次的问题,完美避免了父类构造函数与子类构造函数之间的耦合,也不存在共享父类属性的问题,同时父类原型上的方法可以正常继承。

7.class继承

ES6新增了class关键字,标准化了JavaScript中的继承方式,可以更简洁地实现继承,代码更易读、易写,利于代码的维护。示例代码如下:

class Parent {
    constructor(name) {
        this.name = name;
    }
    getName() {
        return this.name;
    }
}

class Child extends Parent {
    constructor(name, age) {
        super(name);
        this.age = age;
    }
    getAge() {
        return this.age;
    }
}

const child = new Child('lucifer', 20);
console.log(child.getName()); // lucifer
console.log(child.getAge()); // 20

优点:用class实现继承,简化了代码实现的难度,并且代码更加清晰易理解。

综上,以上七种继承方式各有优劣,具体应根据需求场景选择合适的继承方式。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:JavaScript中常见的七种继承及实现 - Python技术站

(0)
上一篇 2023年6月26日
下一篇 2023年6月26日

相关文章

  • 如何在Flutter中嵌套Android布局

    如何在Flutter中嵌套Android布局 在Flutter中,可以通过使用PlatformView来嵌套Android布局。PlatformView允许在Flutter应用程序中嵌入原生视图,这样就可以在Flutter界面中使用Android布局。 下面是在Flutter中嵌套Android布局的完整攻略: 步骤1:创建Android布局 首先,我们需要…

    other 2023年7月28日
    00
  • Win10一周年更新正式版ISO官方光盘镜像免费下载地址

    Win10一周年更新正式版ISO官方光盘镜像免费下载地址攻略 Win10一周年更新正式版ISO官方光盘镜像是微软为Windows 10操作系统发布的重要更新版本。以下是详细的攻略,包括两个示例说明,以帮助您获取免费下载地址。 步骤一:访问微软官方网站 首先,您需要访问微软官方网站以获取Win10一周年更新正式版ISO官方光盘镜像的免费下载地址。请按照以下步骤…

    other 2023年8月4日
    00
  • 机器人操作系统(ros)教程4:ros的框架【转】

    机器人操作系统(ROS)教程4: ROS的框架【转】 ROS是一个流行的机器人操作系统,具有广泛的应用。本篇文章将介绍ROS的框架,帮助读者更好地理解ROS系统的结构,并为想要深入了解ROS系统的用户提供帮助。 ROS系统的结构 ROS系统的设计结构是基于一组相互独立的节点(nodes)的,每一个节点针对特定的任务进行设计和实现。ROS节点可以是C++,Py…

    其他 2023年3月29日
    00
  • 微信QQ如何制作自定义个性化通知铃声?自定义QQ个性提示音

    制作自定义个性化通知铃声的攻略如下: 步骤一:准备音频素材 制作自定义通知铃声需要先准备好音频素材。可以在网上下载自己喜欢的铃声,或者自己录制音频。需要注意的是,铃声长度不要超过30秒,文件格式为mp3格式。 步骤二:将铃声上传到网盘 将制作好的铃声上传到网盘中,这样可以方便地在多个设备之间同步使用自定义通知铃声。建议使用百度网盘或者腾讯微云等大型网盘。 步…

    other 2023年6月25日
    00
  • SpringBoot @ConfigurationProperties使用详解

    SpringBoot @ConfigurationProperties使用详解 在Spring Boot中,@ConfigurationProperties注解是一个非常有用的注解,它可以帮助我们将配置文件中的属性值绑定到Java对象上。这样,我们就可以方便地通过Java对象来获取配置文件中的属性值,而不需要手动解析配置文件。 1. 创建配置类 首先,我们需…

    other 2023年7月28日
    00
  • Linux学习之mkdir命令详解

    Linux学习之mkdir命令详解 mkdir命令是在Linux系统中用于创建新目录的命令。本篇攻略将详细讲解该命令的使用方法及注意事项。 命令格式 mkdir命令的基本语法如下: mkdir [选项] 目录名 其中,选项包括: -m:为新目录设置权限 -p:递归创建目录 常用选项 -m 使用-m选项可以为新目录指定权限。具体用法如下: mkdir -m […

    other 2023年6月26日
    00
  • SpringBoot 项目打成 jar后加载外部配置文件的操作方法

    为了让解释更加清晰,我将分为以下几个步骤来讲解Spring Boot项目打成jar包后加载外部配置文件的操作方法。 1. 添加外部配置文件 在项目的根目录下,添加配置文件,如application.properties或application.yml等。需要注意的是,如果是yml文件,必须注意yml的缩进格式,否则会导致读取错误。 例如,我们添加一个名为co…

    other 2023年6月25日
    00
  • 使用淘宝IP库获取用户ip地理位置

    使用淘宝IP库获取用户IP地理位置攻略 淘宝IP库是一个常用的工具,可以通过用户的IP地址获取其地理位置信息。下面是使用淘宝IP库获取用户IP地理位置的完整攻略。 步骤一:获取用户IP地址 首先,你需要获取用户的IP地址。在Web开发中,可以通过HTTP请求的头部信息中的X-Forwarded-For字段或者REMOTE_ADDR字段来获取用户的IP地址。具…

    other 2023年7月30日
    00
合作推广
合作推广
分享本页
返回顶部