ES6 class关键字 ~ 非常详细

下面的对ES6中class关键字的整理,希望可以帮助到有需要的小伙伴~


传统面向对象是基于类的面向对象,类的继承实际上是构造函数的继承

JSON是基于原型的面向对象

es6 给了JSON类的语法规则,但是底层没有提供类,底层是构造函数。类的继承实际上是构造函数的继承。

// 这个原型指向对象
Hero.prototype = {
    age : 18,
    myJob : function () {
        console.log("eat");
    }
}
var hero = new Hero();

// ES6创建类
class Hero {
    // 构造器
    constructor() {
        this.name = "张无忌";
        this.sayMe = function () {
            console.log("this is 张无忌");
        }
    }
}

类的声明

声明类具有以下两种方式:

  • 类的声明方式

    class name [extends]{
    	// class body
    }
    
    • name: 表示当前声明的类名。

    • extends:继承

      但是不同于类表达式,类声明不允许再次声明已经存在的类,否则将会抛出一个类型错误。

  • 类的表达式方式

    const MyClass = class [className][extends]{
    	// class body
    );
    // 或者
    let MyClass = class [className][extends]{
    	// class body
    );
    // 或者
    var MyClass = class [className][extends]{
    	// class body
    );
    

    和函数表达式相同的一点是,类表达式可以是命名也可以是匿名的。如果是命名类表达式,这个名字只能在类体内部才能访问到。

实例:

/*
    1. 类的声明方式
    class className {
        内部结构
    }
    * class关键字 - 用于创建类
    * className - 创建的类名
    * 使用类的声明方式时–不允许重复声明的

*/

class Hero {}

/*
2.类的表达式方式

    const/let/var className = class [className]{
        内部结构
    }
    * class关键字 – 用于创建类
    * myclass/className - 表示创建的类名
        * myClass -类名,用于后面的代码逻辑进行调用
        * className -类名,用于当前类的内部使用的
*/

const myHero = class Hero {}

// 使用var关键字可以重复声明一个类,其余声明类的方式都不允许重复声明
var myHero2 = class Hero2 {}
var myHero2 = class Hero2 {}



构造函数

构造函数(Constructor )是用于创建和初始化类中创建的一个对象的一种特殊方法。

constructor([arguments]) { ...}
  • 在一个类中只能有一个名为“constructor”的特殊方法。一个类中出现多次构造函数(Constructor)方法将会抛出一个SyntaxError错误。
  • 在一个构造方法中可以使用super关键字来调用一个父类的构造方法。
  • 如果没有显式指定构造方法,则会添加默认的constructor方法。
  • 如果不指定一个构造函数( constructor )方法,则使用一个默认的构造函数( constructor ) 。
/*
    创建类 - 结构
    * 外层的类的语法结构
    * 内层的构造器的语法结构
*/

class Hero {
    // 构造器
    constructor() {
        this.name = "Jenny";
        this.sayMe = () => {
            console.log("this is Jenny");
        }
    }
}

let hero = new Hero();
console.log(hero); // Hero { name: 'Jenny', sayMe: [Function] }
hero.sayMe(); // this is Jenny


getter与setter

与ECMAScript 5一样,在“类”的内部可以使用get和 set 关键字(不可以自己定义),对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

在ES5中,et 和 set 是函数名,可以自己定义

/*// ES5 - get 和 set 是函数名,可以自己定义
function fn() {
    var v = 100; // 局部变量
    return {
        get : function () {
            return v;
        },
        set : function (value) {
            v = value;
        }
    }
}

var obj = fn();
console.log(obj.get()); // 100
obj.set(99);
console.log(obj.get()); // 99*/


/*function fn() {
    var v = 100;
    this.get = function () {
        return v;
    }
    this.set = function (value) {
        v = value;
    }
}

var obj = new fn();
obj.set(999);
console.log(obj.get()); // 999*/

// ES6
// 创建对象的属性 可以 设置和获取
/*class Hero {
    constructor() {
        this.v = 100;
    }
}

var hero = new Hero();
console.log(hero.v); // 100*/

// get 和 set [关键字]
class Hero {
    constructor() {
        this.v = 100;
    }

    get getV() {
        return this.v;
    }

    set setV(value) {
        this.v = value;
    }
}

var hero = new Hero();
console.log(hero); // Hero { v: 100 } 没有get和set方法
hero.getV(); // TypeError: hero.getV is not a function
console.log(hero.v);
console.log();


// 可以设置一个属性  没有自带的 get和set Object.defineProperty

不允许提前声明

声明类时,是不存在声明提前的现象的。如下示例代码所示:

new Foo():// ReferenceError: Foo is not defined
class Foo {}

上述代码示例中,Foo类调用在前,声明在后。由于ECMAScript6不允许类的声明提前,结果为报错。
这种规定的原因与继承有关,必须保证子类在父类之后定义。

不允许重复声明

声明类时,是不存在重复声明的。如果一个类被重复声明的话,则引起解析错误。

如下示例代码所示:

class Foo {};
class Foo {}; // SyntaxError; ldentifier 'Foo' has already been declared

若之前使用类表达式定义了一个类,则再次声明这个类同样会引起解析错误。

let Foo = class {};
class Foo {}}; // SvntaxError; ldentifier 'Foo' has already been declared

静态方法

静态方法的语法

static关键字为一个类定义了一个静态方法。静态方法不会在类的实例(通过类生成的对象)上被调用,相反被类本身调用。

static methodName() {...}

methodName:表示指定类中的静态方法名称。

注意:

静态方法直接在类上进行调用,不能在类的实例上调用。

ES6 实例:

/*
    在类的声明中
    * 构造器和普通方法中的this -> 指代创建后的对象
    * 静态方法中的this -> 指代当前的类
*/

class Hero {
    constructor() {
        this.name = "lucy";
        this.sayMe = ()=>{
            console.log("this is " + this.name); // this指向的是当前对象

            // 在构造器中调用静态方法,
            // 1.类名直接调用 即 类名.静态方法()
            Hero.sayYou(); // this is sayYou
            // 2. this.constructor.静态方法名()
            this.constructor.sayYou(); // this is sayYou
        }
    }
    // 对象的方法有2种 - 可枚举 / 不可枚举
    // 在构造器外面定义方法 - 不可枚举(存在但不能直接打印)
    toString () {
        console.log("name toString" + this.name);
        // this指向的是当前对象
        // return "name toString " + this.name
    }

    static sayYou() {
        console.log("this is sayYou"); // this指向的是当前类
    }

    static sayHe() {
        // 在当前静态方法中,调用另一个静态方法
        this.sayYou();
    }
}

let hero = new Hero();
hero.sayMe(); // this is lucy
console.log(hero.toString()); // undefined toString()方法中没有return语句,是打印不出结果的
// console.log(hero.toString()); // name toString lucy

// 调用sayYou()静态方法
Hero.sayYou(); // this is sayYou
// 调用sayHe()静态方法
Hero.sayHe(); // this is sayYou

类的继承

实现类的继承

类的继承在底层中实际上是 原型的继承

语法:

class ChildClass extends ParentClass {...}
  • extends:使用class创建类的时候,用extends指出该类的父类

注意:

  1. 必须在子类的构造器中写入super(),该super()指向父类的构造器,子类才能获取到父类构造器中的属性和方法

  2. 继承的.prototype必须是一个Object或者null.

class Parent {
    constructor() {
        this.name = 'parent';
        this.sayMe = function() {
            console.log('this is sayme')
        }
    }
    sayYou() {
        console.log("这是父类的一个普通方法"); // 这是父类的一个普通方法  undefined
    }

    static staticMethod() {
        console.log("这是父类的静态方法");
    }
}

// 声明Child类时,指定Child类作为Parent类的子类
class Child extends Parent {
    constructor() {
        super(); // super -> 指向当前子类的父类的构造器,否则获取不到父类构造器中的属性和方法
        this.age = 18;
    }


}

let child = new Child(); //
console.log(child); // Child { name: 'parent', sayMe: [Function], age: 18 }
console.log(child.sayYou()); //这是父类的一个普通方法
console.log(Parent.staticMethod()); // 这是父类的静态方法   undefined

继承于内置对象

写一个类继承于内置对象,基于内置对象扩充自己需要的方法,不会改变内置对象原型的内容。

之前使用原型方法的时候,把自己定义的方法加在了内置方法的原型上,改变了内置方法的原型,是不友好的

实例:

/*// myDate类继承于内置对象Date
class myDate extends Date{
    constructor() {
        super();
    }
    getFormattedDate(){

    }

}

let date = new Date();
console.log(date.getFullYear()); // 2020  只能单独返回年、月、日*/


// 继承于Date内置对象

// myDate类继承于内置对象Date
class myDate extends Date{
    constructor() {
        super();
    }

    // 自己定义方法 返回 年-月-日
    getFormattedDate(){
        var months = ["1月","2月","3月","4月","5月","6月","7月","8月","9月","10月","11月","12月"];
        //            日         -          月                    -          年
        return this.getDate() + "-" + months[this.getMonth()] +  "-" + this.getFullYear();
    }

}

/*
let date = new Date();
console.log(date.getFullYear()); // 2020  只能单独返回年、月、日*/

let date = new myDate();
console.log(date.getFormattedDate()); // 25-12月-2020

// 2.继承于数组
let arr = [1,2,3,4,5,4,3,2,1];
class MyArray extends Array {
    constructor() {
        super();
    }
    // Set数据结构中的值是唯一的,可以利用Set给数组中的值去重
    quchong(array) {
        return new Set(array);
    }
}

var array = new MyArray();
console.log(array.quchong(arr)); // Set { 1, 2, 3, 4, 5 }

Super关键字

super关键字可以当作函数使用、当作对象使用。这两种情况是不同的。

  • super关键字当作函数调用 - 代表父类的构造函数

    ES6要求子类的构造函数必须执行一次super函数

    注意:

    super虽然代表了父类A的构造函数,但是返回的是子类B的实例

    即 super内部的 this指的是B,因此 super()在这里相当于A.prototype.constructor.call(this)。

  • super关键字作为对象

    • 在普通方法中,指向父类的原型对象
    • 在静态方法中,指向父类

    注意:

    由于super指向父类的原型对象,super()不能调用定义是父类实例上的方法和属性。

类的实例

注意:父类中方法的返回值 必须用 return , 否则会返回undefined

// 定义一个类
class Parent {
    // 当前的构造器(如果省略,JS会自动生成一个构造器)- 创建对象的初始化方法
    constructor(name) {
        this.name = name;
    }
    // 当前类的(实例对象的)方法,不是当前类的原型方法
    toString() {
        console.log("this is toString method");
    }
    // 静态方法 - 由当前类直接调用的方法
    static staticMethod() {
        return "this is static method";
    }

    
}

// super作为对象,在普通方法中指向父类的原型对象,所以父类中的toString()方法必须是原型中的方法
    // 在类的原型中添加方法
    Parent.prototype.sayMe = function () {
        return "this is parent method."
    }




// 类也同样具有原型(类似于ES5中的构造函数)
// 对象中有一个隐式原型 - 指向类的原型
/*let parent = new Parent();
parent.toString(); // this is parent method.*/


// 定义一个类作为另一个类的子类
class Child extends Parent {
    // 因为父类的构造函数中有一个name形参,所以子类的构造函数中也要有和父类一样是形参,否则子类就不能继承父类了
    // 别忘了 super()里面也要写上父类中构造函数的形参
    constructor(name,age) {
        super(name); // super指向父类的构造器
        this.age = age;
        // 以下用法:super -> 指向父类的实例对象(具有隐式原型)
        //  原型对象不能调用实例对象,实例对象能调用原型对象
        super.sayMe(); // super指向父类的原型对象

        // super.staticMethod(); // 报错 TypeError: (intermediate value).sayMe is not a function

        super.toString(); // super指向父类实例化的对象 this is tostring method .

        // super的不同用法导致super的含义不同
    }

    sayMe() {
        // super 指向父类的原型对象
        console.log("this is child method. " + super.sayMe())
    }

    static staticMethod() {
        // super - 指向父类
        console.log("this is child static method. " + super.staticMethod())
    }
}

// 因为子类的构造函数中有形参name 和 age , 所以实例化子类的时候也要给形参传值
let child = new Child("lucy",18);
// console.log(child); // Child { name: 'lucy', age: 18 }
// 父类和子类中有相同函数名toString(),当子类对象调用该方法的时候,子类和父类的相同方法会被同时调用
child.sayMe();
/*
this is parent method.
this is child method. undefined

如果 super.staticMethod() 的返回值是 undefined
原因:super作为对象,在普通方法中指向父类的原型对象,而父类中的toString()方法不是原型中的方法

把父类中的toString()方法改为原型中的方法后:
返回结果是:
this is child method. this is parent method.
*/


// Child.staticMethod();
/*
this is static method
this is child static method. undefined
*/

end~
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值