js学习笔记之class类、super和extends关键词
admin
2023-05-01 07:11:57
目录

    前言

    JavaScript 语言在ES6中引入了 class 这一个关键字,在学习面试的中,经常会遇到面试官问到谈一下你对 ES6 中class的认识,同时我们的代码中如何去使用这个关键字,使用这个关键字需要注意什么,这篇来总结一下相关知识点。

    正文

    1.es6之前创建对象

    先来看下es6之前我们要想创建一个对象,只能通过构造函数的方式来创建,将静态方法添加在原型上面使得每一个实例能够调用该方法。

    function Person(name, age) {
                this.name = name
                this.age = age
                Person.prototype.sayHello = function () {
                    return "hello," + this.name + ",早上好"
                }
            }
            let person = new Person("serendipity", 18)
            console.log(person.sayHello())//hello,serendipity,早上好
            console.log(person instanceof Person);//true
            console.log(person instanceof Object);//true

    2.es6之后class的声明

    类是用于创建对象的模板,他们用代码封装数据以处理该数据。js中的 class 类建立在原型之上,但也具有某些语法和语义与ES5类相似语义共享。

    实际上,类是一种特殊的函数,就像定义函数声明和函数表达式一样,类的语法也有两个部分组成:类声明和类表达式。

    class Person {
                constructor(name, age) {//自有属性,该属性出现在实例上,只能在类的构造器或者方法内部进行创建
                    this.name = name
                    this.age = age
                }
                sayHello() {//等价于Perosn.prototype.sayHello
                    return `hello,${this.name},早上好`
                }
            }
            let person = new Person("serendipity", 18)
            console.log(person.sayHello());//hello,serendipity,早上好
            console.log(person instanceof Person);//true
            console.log(person instanceof Object);//true
            console.log(typeof Person);//function
            console.log(typeof Person.prototype.sayHello);//function

    类声明允许在class中使用 constructor 方法定义一个构造器,而不需要定义专门的构造方法来当构造器使用。

    class 类的语法与普通es5之前的函数语法相似,但是还存在一些特性需要注意:

      (1)类的声明不会被提升,类的声明行为和 let 相似,因此执行时类会存在暂时性死区;

      (2)类中所有代码自动运行在严格模式下,且改严格模式无法退出

      (3) 类中所有方法都是不可枚举的,普通自定义方法只有通过 object.defineProperty() 才能将方法定义为不可枚举

      (4)类中的所有方法内部都没有 [[construct]] ,因此使用new 来调用他们会抛出错误

      (5)调用类构造器时不使用 new 会抛出错误

      (6)试图在类的方法内部重写类名会抛出错误

    将上面的代码转换为ES5之前的写法如下:

    let PersonClass = (function () {
                "use strict"
                const PersonClass = function (name, age) {
                    // 判断是否被new调用构造函数
                    if (typeof new.target === "undefined") {
                        throw new Error("Constructor must be call with new.")
                    }
                    this.name = name
                    this.age = age
                }
                Object.defineProperty(PersonClass.prototype, "sayHello", {
                    value: function () {
                        if (typeof new.target !== "undefined") {//保正调用时没有使用new
                            throw new Error("Method cannot be called with new.")
                        }
                        return "hello," + this.name + ",早上好!"
                    },
                    enumerable: false,
                    configurable: true,
                    writable: true
                })
                return PersonClass
            })()
            var personClass = new PersonClass("serendipity", 18)
            console.log(personClass.name);//serendipity
            console.log(personClass.sayHello());///hello,serendipity,早上好!

    两个PersonClass 声明,一个在外部作用域的 let 声明,另一个在立即执行函数内部的 const 声明,这就是为何类的方法不能对类名进行重写,而类的外部的代码则被允许。同时,只在类的内部类名才被视为使用了const声明,这意味着你可以在外部(相当于let)重写类名,但是不能在类的方法内部这么写。

    3.类的继承

    ES6之前的继承方式主要通过构造函数和原型链组合的方式来实现继承,具体代码如下:

    function Rectangle(length, width) {
                this.length = length
                this.width = width
                Rectangle.prototype.getArea = function () {
                    return this.length * this.width
                }
            }
            function Square(length) {
                Rectangle.call(this, length, length)
            }
            Square.prototype = Object.create(Rectangle.prototype, {
                constructor: {
                    value: Square,
                    enumerble: true,
                    writeable: true,
                    configurable: true
                }
            })
            var square = new Square(3)
            console.log(square.getArea());//9
            console.log(square instanceof Square);//true
            console.log(square instanceof Rectangle);//true

    上面的代码通过构造函数和原型上面添加静态方法实现了 Rectangle 父类,然后子类 Square 通过 Rectangle.call(this,length,length) 调用了父类的构造函数,Object.create 会在内部创建一个空对象来连接两个原型对象,再手动将 constructor 指向自身。这种方法实现继承代码繁杂且不利用理解,于是ES6 class 类的创建让继承变得更加简单,使用extends 关键字来指定当前类所需要继承的父类,生成的类的原型会自动调整,还可以使用 super() 方法来访问基类的构造器。具体代码如下:

    class Rectangle {
                constructor(length, width) {
                    this.length = length
                    this.width = width
                }
                getArea() {
                    return this.length * this.width
                }
            }
            class Square extends Rectangle {
                constructor(length) {
                    super(length, length)
                }
                getArea() {
                    return this.length + this.length
                }
    
            }
            var square = new Square(3)
            console.log(square.getArea());//6
            console.log(square instanceof Square);//true
            console.log(square instanceof Rectangle);//true

    上面的代码中 Square 类重写了基类的 getArea() 方法,当派生的子类中函数名和基类中函数同名的时候,派生类的方法会屏蔽基类的方法,同时也可以再子类中getArea () { return super.getArea() }中调用基类的方法进行扩展。

    4.继承类的静态成员

    静态成员:直接在构造器上添加的额外的方法。例如ES5中在原型上添加的方法就属于静态成员,ES6 class类引入简化了静态成员的创建,只需要在方法与访问器属性的名称前添加 static关键字即可。例如下面的代码用于区分静态方法和实例方法。

    function PersonType(name) {
            this.name = name;
        }
        // 静态方法
        PersonType.create = function(name) {
            return new PersonType(name);
        };
        // 实例方法
        PersonType.prototype.sayName = function() {
            console.log(this.name);
        };  var person = PersonType.create("Nicholas");

    在ES6中要想使用静态成员如下:

    class Rectangle {
                constructor(length ,width) {
                    this.length = length
                    this.width = width
                }
                getArea() {
                    return this.length * this.width
                }
                static create(length,width) {
                    return new Rectangle(length , width)
                }
            }
            class Square extends Rectangle{
                constructor (length){
                    super(length,length)
                }
            }
            var square =Square.create(3,4)
            console.log(square.getArea());//12
            console.log(square instanceof Square);//false
            console.log(square instanceof Rectangle);//true

    上面的代码中,一个新的静态方法 create() 被添加到 Rectangle 类中,通过继承,以Square.create() 的形式存在,并且其行为方式与Rectangle.create() 一样。需要注意静态成员不懂通过实例来访问,始终需要直接调用类自身来访问他们。

    写在最后

    以上就是本文的全部内容,希望给读者带来些许的帮助和进步,方便的话点个关注,小白的成长踩坑之路会持续更新一些工作中常见的问题和技术点。

    相关内容

    热门资讯

    苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
    北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
    世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
    长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
    应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
    猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
    猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
    阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
    脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
    demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
    苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
    北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
    应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
    长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
    世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
    阿西吧是什么意思 阿西吧相当于... 即使你没有受到过任何外语培训,你也懂四国语言。汉语:你好英语:Shit韩语:阿西吧(아,씨발! )日...
    脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
    demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
    北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...