js 调用class_ES6 的新鲜玩意儿——class

本文探讨了ES6中的class关键字,包括如何通过class创建对象、实现继承,以及对多态、重载和重写的理解。虽然ES6的class不支持多继承和重载,但支持方法重写。同时,文章提到了ES6的原型链依然保留在_proto_中。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这玩意是期待好久,终于要回归到了久违的感觉。我们先撸完es6的class,再来重温es5的类。

面向对象开发三巨头:封装、多态、继承。在后端语言中这是天天得念叨的,只是js真的好像不怎么说起,似乎真的是没有这几个概念。或许是js对这几个概念处理太过于自由,有太多的办法来展现,所以就有那么一点儿不在意。或许是我使用js只是在非常简单的功能,自己内功不行。下面回归es6的class,不过虽然es6加上了class,还是缺少了接口,面向抽象开发好像在js还是有些不可行。

先来讲几个概念:面向对象、封装、多态、继承、重载。

1、面向对象:任何物体都是一个独立对象,任何物体都可划分到自己的分类。这与物与类聚,人以群分多少有相似的感觉。面向对象就是将所有的概念或者物体抽象成不同的类,然后以类为基础进行属性与行为的封装。最后将各行为个体以类为单位进行生成,一般都是以new 关键字来进行生成对象。最后将各个不同的对象进行有机组合,形成系统。

2、封装:在面向对象思想中,封装是以一个类做基础框架的,封装是在类中进行的,封装就是对一个个类的属性、行为有机表示(当然也可以通过继承得来),以形成类的灵魂。

3、多态:多态就是对象的生成可以有多种形式,这种多是基于继承的基础之上。使用专业的口头语就是父类对象指向子类地址。

4、重载:一个类中的相同行为的入参不同。

5、重写:子类对象对继承来的方法注入自己的逻辑,覆盖了父类的逻辑。

以上的概念是我对C#语言的面向对象的理解,希望es6 对这些概念不要有颠覆概念。

撸码之前,我们先提几个问题:

1、es6基于class如何new 对象的?

2、es6基于class如何继承的?

3、es6是否能够同时继承多个类?

4、es6是否有多态,如何表示?

5、es6是否重载?

6、es6是否可以重写?

7、es6 原型链是如何的?

如果解决了上面几个问题,es6的基于class的面向对象开发就到味了。废话少说,撸起。

1、类的封装及实例创建

/*****
 * 工程师类
 */
class Engineer{
    /***
     * 构造函数
     */
    constructor(name){
        this.name = name;
    }

    /****
     * 不能使用let、const、var 等修饰符
     */
    work="";

    /***
     * 心态好,永远18岁
     */
    age = 18;

    /****
     * 介绍我的名字,不能在前面加function
     */
    introduce(){
        console.log(`myName is:${this.name}`);
        console.log(`myWork is:${this.work}`);
        console.log(`age is:${this.age}`);
    }
}
//使用 new 来创建一个实例对象
let engineer = new Engineer("爱钱的大笨蛋");
engineer.introduce();//调用实体方法(函数/行为)

类名称要符合帕斯卡(Pascal)命名法,这个是开发人员的小规范。上面的代码回答了第1个问题,es6中的类可以直接 new 类模板,便可以创建一个实例对象。有一个非常重要的注意点是,变量不允许使用var、let、const来修饰,行为不允许使用function来修饰。上面的例子在实例化的时候传入了需要的变量name,其他二个属性直接在类模板中进行默认配置。

2、继承

/*****
 * 工程师类
 */
class Engineer{
    /***
     * 构造函数
     */
    constructor(name){
        this.name = name;
    }

    /***
     * 名称
     */
    name="";

    /****
     * 不能使用let、const、var 等修饰符
     */
    work="";

    /***
     * 心态好,永远18岁
     */
    age = 18;

    /***
     * 使用语言列表
     */
    languageArr=[];

    /****
     * 介绍我的名字,不能在前面加function
     */
    introduce(){
        console.log(`myName is:${this.name}`);
        console.log(`myWork is:${this.work}`);
        console.log(`age is:${this.age}`);
    }

    /**
     * 写代码
     * 
     */
    writeCode(){
        console.log(`code language is:${this.languageArr}`);
    }
}
//使用 new 来创建一个实例对象
//let engineer = new Engineer("爱钱的大笨蛋");
//engineer.introduce();//调用实体方法(函数/行为)
class WebEngineer extends Engineer{
    /***
     * 构造函数,一创建的时候便可以设置变量值
     */
    constructor(name,languageArr){
       super(name);//父类的构造函数调用

       this.languageArr = languageArr;//通过传进去的值来初始化我的变量(属性)
       this.work = "我的工作主要是做前端开发工作";//直接初始化我的变量(属性)
    }

    dream(){
        console.log("我是一个喜欢做梦想的人,想象着有自己的大帝国,乌拉")
    } 
}
let webEngineer = new WebEngineer("前端开发",["css","js","html"]);
webEngineer.introduce();//自我介绍,此方法继承于Engineer类
webEngineer.writeCode();//写代码,此方法继承于Engineer类
webEngineer.dream();//这个是我自己的方法,我扩展的方法

继承可以让我们更加方便封装代码,并且极大的进行了代码重用。子类通过继承可以快速的封装出父类的属性与行为。当然也可以自己进行扩展,例如上面的dream()方法。由于es6中没有对变量的public、protected、private等修饰符,所以子类将全部继承了父类的所有属性及方法。

3、es6是否能够同时继承多个类?

class Manager{
    managerProject(){
        console.log("我开始管理项目")
    }
}
/*****
 * 工程师类
 */
class Engineer{
    /***
     * 构造函数
     */
    constructor(name){
        this.name = name;
    }

    /***
     * 名称
     */
    name="";

    /****
     * 不能使用let、const、var 等修饰符
     */
    work="";

    /***
     * 心态好,永远18岁
     */
    age = 18;

    /***
     * 使用语言列表
     */
    languageArr=[];

    /****
     * 介绍我的名字,不能在前面加function
     */
    introduce(){
        console.log(`myName is:${this.name}`);
        console.log(`myWork is:${this.work}`);
        console.log(`age is:${this.age}`);
    }

    /**
     * 写代码
     * 
     */
    writeCode(){
        console.log(`code language is:${this.languageArr}`);
    }
}
//使用 new 来创建一个实例对象
//let engineer = new Engineer("爱钱的大笨蛋");
//engineer.introduce();//调用实体方法(函数/行为)
//同时继承多个类进行测试
class WebEngineer extends Engineer,Manager{
    /***
     * 构造函数,一创建的时候便可以设置变量值
     */
    constructor(name,languageArr){
       super(name);//父类的构造函数调用

       this.languageArr = languageArr;//通过传进去的值来初始化我的变量(属性)
       this.work = "我的工作主要是做前端开发工作";//直接初始化我的变量(属性)
    }

    dream(){
        console.log("我是一个喜欢做梦想的人,想象着有自己的大帝国,乌拉")
    } 
}
let webEngineer = new WebEngineer("前端开发",["css","js","html"]);
webEngineer.introduce();//自我介绍,此方法继承于Engineer类
webEngineer.writeCode();//写代码,此方法继承于Engineer类
webEngineer.dream();//这个是我自己的方法,我扩展的方法

上面的代码直接报错,如图:

60dd4bb953e278eeec6fb76c7079f4db.png

由上可见,es6不支持同时继承多个类,会报语法错误。

4、es6是否有多态,如何表示?

在C# 中多态是父类对象指向子类地址,生成的对象是以子类为模板的。可是es6对变量的修饰符只有let、const、var,代表的是变量作用域。在网上看了几篇es6多态的文章,感觉还都是直接new 类,并没有像高级语言那样以父类对象指向子类地址的方式生成。所以我不好说到底有没有多态,依我的观点,这样的写法不算是多态,多态就是可以多种方式生成对象实例,直接new 是一种,以父类对象生成是另外一种。可是现在es6只有直接new 的这种,就不好下结论。大家就百度 es6 多态 来获取知识吧。

5、es6是否重载?

js本身就是弱语言,一个方法你可以通过直接传入不同的入参来获取参数,arguments 对象就包含了所有的参数。所以es6类中如果有多个相同名称的方法,最后的那个将直接替换掉前面的方法。所以,es6没有重载的方法。如下代码,通过debugger可以知道,dream方法永远只执行最后的那个dream(myDream,otherDream) 方法体。

class Manager{
    managerProject(){
        console.log("我开始管理项目")
    }
}
/*****
 * 工程师类
 */
class Engineer{
    /***
     * 构造函数
     */
    constructor(name){
        this.name = name;
    }

    /***
     * 名称
     */
    name="";

    /****
     * 不能使用let、const、var 等修饰符
     */
    work="";

    /***
     * 心态好,永远18岁
     */
    age = 18;

    /***
     * 使用语言列表
     */
    languageArr=[];

    /****
     * 介绍我的名字,不能在前面加function
     */
    introduce(){
        console.log(`myName is:${this.name}`);
        console.log(`myWork is:${this.work}`);
        console.log(`age is:${this.age}`);
    }

    /**
     * 写代码
     * 
     */
    writeCode(){
        console.log(`code language is:${this.languageArr}`);
    }
}
//使用 new 来创建一个实例对象
//let engineer = new Engineer("爱钱的大笨蛋");
//engineer.introduce();//调用实体方法(函数/行为)
class WebEngineer extends Engineer{
    /***
     * 构造函数,一创建的时候便可以设置变量值
     */
    constructor(name,languageArr){
       super(name);//父类的构造函数调用

       this.languageArr = languageArr;//通过传进去的值来初始化我的变量(属性)
       this.work = "我的工作主要是做前端开发工作";//直接初始化我的变量(属性)
    }

    dream(){
        console.log("我是一个喜欢做梦想的人,想象着有自己的大帝国,乌拉");
    } 
    dream(myDream){
        console.log("这是重载中有一个方法的dream");
    }
    //重载构造中,永远都会只执行最后的那个方法
    dream(myDream,otherDream){
        console.log("这是重载中有二个方法的dream");
    }
}
let webEngineer = new WebEngineer("前端开发",["css","js","html"]);
webEngineer.introduce();//自我介绍,此方法继承于Engineer类
webEngineer.writeCode();//写代码,此方法继承于Engineer类
webEngineer.dream();//这个是我自己的方法,我扩展的方法
webEngineer.dream("重载测试一个参数");//这个是我自己的方法,我扩展的方法
webEngineer.dream("重载测试二个参数");//这个是我自己的方法,我扩展的方法

6、es6是否可以重写?

如下面的代码:

class Manager{
    managerProject(){
        console.log("我开始管理项目")
    }
}
/*****
 * 工程师类
 */
class Engineer{
    /***
     * 构造函数
     */
    constructor(name){
        this.name = name;
    }

    /***
     * 名称
     */
    name="";

    /****
     * 不能使用let、const、var 等修饰符
     */
    work="";

    /***
     * 心态好,永远18岁
     */
    age = 18;

    /***
     * 使用语言列表
     */
    languageArr=[];

    /****
     * 介绍我的名字,不能在前面加function
     */
    introduce(){
        console.log(`myName is:${this.name}`);
        console.log(`myWork is:${this.work}`);
        console.log(`age is:${this.age}`);
    }

    /**
     * 写代码
     * 
     */
    writeCode(){
        console.log(`code language is:${this.languageArr}`);
    }
}
//使用 new 来创建一个实例对象
//let engineer = new Engineer("爱钱的大笨蛋");
//engineer.introduce();//调用实体方法(函数/行为)
class WebEngineer extends Engineer{
    /***
     * 构造函数,一创建的时候便可以设置变量值
     */
    constructor(name,languageArr){
       super(name);//父类的构造函数调用

       this.languageArr = languageArr;//通过传进去的值来初始化我的变量(属性)
       this.work = "我的工作主要是做前端开发工作";//直接初始化我的变量(属性)
    }

    dream(){
        console.log("我是一个喜欢做梦想的人,想象着有自己的大帝国,乌拉");
    } 
    
    /****
     * 重写的方法,此方法将覆盖父类方法的writeCode
     */
    writeCode(){
        console.log("我不需要写代码,我只想money");
    }
}
let webEngineer = new WebEngineer("前端开发",["css","js","html"]);
webEngineer.introduce();//自我介绍,此方法继承于Engineer类
webEngineer.writeCode();//写代码,此方法继承于Engineer类,同时我自己也有,看看执行了哪个
 

执行结果如下:

0bf79ba19d241f5b60abbdf73a483874.png

从结果可以看出,确实是执行了子类的writeCode方法,说明es6的重写是存在的。

7、es6 原型链是如何的?

先看代码:

class People{
    constructor(name){
        this.name = name;
    }
}
/*****
 * 工程师类
 */
class Engineer extends People{
    /***
     * 构造函数
     */
    constructor(name){
        super(name);
        this.name = name;
    }

    /***
     * 名称
     */
    name="";

    /****
     * 不能使用let、const、var 等修饰符
     */
    work="";

    /***
     * 心态好,永远18岁
     */
    age = 18;

    /***
     * 使用语言列表
     */
    languageArr=[];

    /****
     * 介绍我的名字,不能在前面加function
     */
    introduce(){
        console.log(`myName is:${this.name}`);
        console.log(`myWork is:${this.work}`);
        console.log(`age is:${this.age}`);
    }

    /**
     * 写代码
     * 
     */
    writeCode(){
        console.log(`code language is:${this.languageArr}`);
    }
}
//使用 new 来创建一个实例对象
//let engineer = new Engineer("爱钱的大笨蛋");
//engineer.introduce();//调用实体方法(函数/行为)
class WebEngineer extends Engineer{
    /***
     * 构造函数,一创建的时候便可以设置变量值
     */
    constructor(name,languageArr){
       super(name);//父类的构造函数调用

       this.languageArr = languageArr;//通过传进去的值来初始化我的变量(属性)
       this.work = "我的工作主要是做前端开发工作";//直接初始化我的变量(属性)
    }

    dream(){
        console.log("我是一个喜欢做梦想的人,想象着有自己的大帝国,乌拉");
    } 
    
    /****
     * 重写的方法,此方法将覆盖父类方法的writeCode
     */
    writeCode(){
        console.log("我不需要写代码,我只想money");
    }
}
let webEngineer = new WebEngineer("前端开发",["css","js","html"]);
webEngineer.introduce();//自我介绍,此方法继承于Engineer类
webEngineer.writeCode();//写代码,此方法继承于Engineer类,同时我自己也有,看看执行了哪个

fec840d34ad950f877719d1d735c7326.png

由上图可以看的出es6的原型链还是保存在_proto_ 中。与es5没有什么区别。

好了,es6的class知识就介绍完整了,相对来说比es5要简单很多。为了更加深入理解js面向对象开发,下一篇介绍es5的面向对象开发。咱们算的上是多情汉子,抱得新欢牵旧爱嘛。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值