深入浅出JavaScript继承(多态篇)

我心飞翔 分类:javascript

一. 前言

我们知道面向对象的三个特性是:封装,继承,多态。

  1. 封装:对外隐藏类的属性和实现细节(如private,protect属性),对外提供公共接口来提供属性读取和修改行为(如c++,java语言中的set构造器,get构造器函数等),以及只对外暴露需要公开的属性和方法。

  2. 继承:子类拥有基类的行为和属性,并可以在以上扩展。例如:人类生物学的遗传。

  3. 多态:同一种方法不同对象之间的响应,即同一个操作作用于不同的对象上,可以产生不同的解释和不同的执行结果。例如:我们右键打开任何一个文件,调用打开方法,MP4调用后是视频播放器播放该视频,MP3是音乐播放器播放改音乐,图片打开的是图片预览程序。这就是多态。

在前两篇文章,我们的知识点几乎都在讲封装和继承两大特性,本章来讲讲JavaScript语言中多态的实现方式。

二. 基本思想

核心思想:通过一个函数,函数的形参是超类(顶级类)的引用,函数体直接调用该方法即可。

Tips: 由于js是弱语言类型;形参任意,然后调用相应方法即可

首先看以下java代码多态的实现:

    package juejinBlog;
// 超类: 文件
abstract class File {
protected String name;
// 构造函数
File(String name) {
this.name = name;
}
public abstract void open();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
};
// 子类:视频文件
class Video extends File {
// 构造函数
Video(String name) {
super(name);
}
@Override
public void open() {
System.out.println("打开了视频文件:"+this.name);
}
}
// 子类:图片文件
class Image extends File {
Image(String name) {
super(name);
}
@Override
public void open() {
System.out.println("打开了图片文件:"+this.name);
}
}
// 测试类
public class Polymorphism {
// 核心方法,作用就是弱化类型,用一个抽象对象代替N种实现。
public static void openFile(File file) {
file.open();
} 
// 主函数
public static void main(String[] args) {
Video mp4 = new Video("企业宣传视频.mp4");
Image img = new Image("图片1.png");
System.out.println(mp4.getName());
System.out.println(img.getName());
openFile(mp4);
openFile(img);
}
}

运行结果如下:

image.png

分析:我们观察核心方法openFile,我们可以观察到形参是一个顶级类的引用,函数体直接调用open方法。当我们调用openFile时传入不同的子类实例时我们发现自动调用了相应类的open方法;java的多态实现是非常简单的。

tips: java自动进行了类型转换,不需要我们进行判断。

三. JavaScript中的多态实现。

我们模拟java中核心方法的实现,看我们是否能完成多态,我们看以下代码。

超类:文件类

    // file.js
class File {
__name = "";
constructor(name) {
if (new.target === File) {
throw new Error("抽象类不能被实例化");
}
this.__name = name;
}
setFileName(name) {
this.__name = name;
}
getFileName() {
return this.__name;
}
open() {}
}
export default File;

子类:视频类

  // video.js
import File from "./file";
class Video extends File {
constructor(name) {
super(name);
}
open() {
console.log(`打开了视频文件${this.__name}`);
}
}
export default Video;

子类:图片类

//image.js
import File from "./file";
class Image extends File {
constructor(name) {
super(name);
}
open() {
console.log(`打开了图片件${this.__name}`);
}
}
export default Image;

测试文件:index.js

import Image from "./mutipleSector/image";
import Video from "./mutipleSector/video";
// 核心方法
function openFile(file) {
file.open();
}
let mp4 = new Video("我的视频.mp4");
let image = new Image("我的图片.png");
console.log(mp4.getFileName());
console.log(image.getFileName());
openFile(mp4);
openFile(image);

运行结果:

image.png

不管你有多少子类,只要调用openFile(

四. 结论

多态其实是强类型结的果,对于强类型语言,如C++、C#、Java,通常采用抽象类或者接口,进行更高一层的【抽象】(本例中使用的File类)。

本质上是为了【弱化具体类型】(用一个【抽象】代替N种具体实现,java例中的openFile方法)。

如java例子中我们添加两行到main函数中:

    // 弱化具体类型
File f1 = new Video("测试视频文件.avi");
File f2 = new Image("测试图片文件.png");
f1.open();
f2.open();

运行结果如图:

image.png

我们发现js中其实多态的实现是非常容易的,即函数传参。其原因就是js语言的特性:本身就是弱类型性

  1. 多态其实是强类型结的果。

  2. 而对于JS这种本身就是【弱类型】的语言来说,多态是与生俱来的。

回复

我来回复
  • 暂无回复内容