ES6 Class和Class继承

1.class的基本语法

class可以理解为是一个语法糖,将js只能通过构造函数创建实例的方法进行了补充

构造函数:

javascript 复制代码
function Person ({ name, age=18 }) {
  this.name = name
  this.age = age
}
new Person({name: '张三'})

Class类:

javascript 复制代码
class Person {
  constructor ({ name, age=18 }) {
    this.name = name
    this.age = age
  }
}
new Person({name: '张三'})

2.深入了解class的特性

  • class的数据类型是一个函数

  • class的原型的constructor指向class

  • 通过new关键字创建出来的实例的constructor指向class

  • class内部的方法是定义在实例的原型上,class内部的属性和constructor里面的方法和属性定义在实例上(构造函数方法定义在实例的原型上,属性定义在实例上 )

  • 通过类创建对象的本质是调用类的constructor,如果类未定义constructor,则会在使用时默认添加。

  • class不能直接调用,需要通过new关键字(构造函数可以直接调用,也可以new 创建实例)

  • class内部方法this指向的是实例,class内部是严格模式(严格模式下不存在变量提升)

  • class中箭头函数的this和普通函数的指向不同:class上面定义的普通函数是在实例的原型上箭头函数this指向定义位置所在的作用域即实例本身,通过解构出来的方法直接调用普通函数的this是undefined,箭头函数是当前实例

  • class可以有取值函数(getter)和存值函数(setter)

  • 类的属性名可以动态设置

  • 静态方法/属性,通过在属性和方法前添加static关键字,静态方法和属性不会被实例继承

  • 静态方法里面的this指向的是类而不是实例,所以静态方法里面this === A

  • class定义实例的属性 直接" 属性名=属性值"

1. class的数据类型是一个函数

javascript 复制代码
  console.log(typeof class A {})

2. class的原型的constructor指向class(类比:构造函数的原型的constructor指向构造函数)

javascript 复制代码
    class A {}
    console.log(A.prototype.constructor === A)

3. 通过 new 关键字创建出的实例的constructor指向该class(类比:new构造函数创建的实例的constructor指向构造函数本身)

javascript 复制代码
    class A {}
    var a = new A()
    console.log(a.constructor === A)

4. class内部的方法实际上都是定义在类实例的prototype上;属性定义在实例上;constructor中的方法和实例都定义在原型上

javascript 复制代码
    class A {
      fn () {}
      toString() {}
    }

    var a = new A()
    console.log(a);

5.通过类创建对象的本质是调用类的constructor,如果类未定义constructor,则会在使用时默认添加。

javascript 复制代码
    class A {
      constructor () {
        this.name = 'a';
        this.fn = function() {};
      }
      fn1() {}
    }
    console.log(new A())

6. class不能直接调用,需要通过new关键字(构造函数可以直接调用,也可以new 创建实例)

7. class内部方法this指向的是实例,class内部是严格模式(严格模式下不存在变量提升)

注意方法如果单独使用会报错,class内部是严格模式,所以 this 实际指向的是undefined

普通函数通过实例调用可调用:但是直接结构后调用,普通函数没有找到是谁调用就会报错 。将普通函数改为箭头函数后,箭头函数定义位置在class中,所以this表示当前类的实例的原型

javascript 复制代码
    class Logger {
      printName(name = 'world') {
        console.log(this, 'this')
        this.print(`Hello ${name}`)
      }
      print(text) {
        console.log(text)
      }
    }

    // let logger = new Logger();
    // // 通过实例调用可以调用
    // logger.printName()
    let {printName} = new Logger();
    printName(); //没有找到谁调用会报错
javascript 复制代码
    class Logger {
      printName = (name = 'world') => {
        // 类中方法的this指向当前class的实例
        console.log(this, 'this')
        this.print(`Hello ${name}`)
      }
      print = (text) => {
        console.log(text)
      }
    }
    let { printName } = new Logger();
    printName(); //没有找到谁调用会报错

分析:

  • 1.this 实际指向的是undefined,如果想要可以正常调用,可以使用箭头函数(箭头函数的this是由定义位置决定,所以就能获取到this为当前实例)

注意:本身class上面定义的普通函数,是在实例的原型上,但是如果使用的是箭头函数,则当前属性和函数就在类的实例上面了

为什么还能箭头函数中printName还能打印出this?因为箭头函数定义本身没有this,所以它的this的位置指向的是当前实例

  • 2.this 实际指向的是undefined,在constructor中对printName进行bind改写this

8.class中箭头函数的this和普通函数的指向不同:class上面定义的普通函数是在实例的原型上箭头函数this指向定义位置所在的作用域即实例本身,通过解构出来的方法直接调用普通函数的this是undefined,箭头函数是当前实例

javascript 复制代码
    class Logger {
      printName(name = 'world') {
        console.log(this, 'this')
        this.print(`Hello ${name}`)
      }
      print(text) {
        console.log(text)
      }
    }

    console.log(new Logger());
javascript 复制代码
    class Logger {
      printName = (name = 'world') => {
        // 类中方法的this指向当前class的实例
        console.log(this, 'this')
        this.print(`Hello ${name}`)
      }
      print = (text) => {
        console.log(text)
      }
    }
    console.log(new Logger());

3.构造函数与class的区别?结合上面的几个特性回答

  • class只能通过new关键字调用
  • class内部是严格模式(直接解构出方法执行this会返回undefined)
  • class里面定义的方法和属性都在实例的原型上,constructor里面定义的属性和方法才在实例上;构造函数方法定义在实例的原型上,属性定义在实例上
  • class可以通过static关键字来定义静态方法

4.class的取值函数(getter)和存值函数(setter)

设置后就可以通过实例设置和获取值时触发这两个方法

javascript 复制代码
    class A {
      get name() {
        return '1'
      }
      set name(value) {
        console.log('setter:' + value)
      }
    }

    var a = new A()
    console.log(a.name);
    a.name = "lmf"

5.类的属性名可以动态设置

javascript 复制代码
    let methodName = 'test'
    class A {
      [methodName] () {
        console.log("test-----");
      }
    }

    var a = new A()
    a.test()

6.静态方法/属性

通过在属性和方法前添加static关键字,静态方法和属性不会被实例继承;静态方法和普通方法可以重名

javascript 复制代码
    class A {
      static fn () {
    //静态方法的this指的是类,所以这里this.getValue() === A.getValue()
        this.getValue()
        console.log(this === A);//true
      }
      static getValue () {
        console.log('张三')
      }
      getValue() {
        console.log('李四')
      }
    }

    var a = new A()
    A.getValue()
    a.getValue()
    A.fn();//静态方法的this指的是类,所以这里this.getValue() === A.getValue()

7.静态方法里面的this指向的是类而不是实例

8.定义实例的属性

javascript 复制代码
class A {
  a = 1
  b = 'SUCCESS'
}

9. 类的继承

  • 类的继承通过extends关键字
  • 子类中的constructor不写时会隐式生成一个constructor函数,如果显示写了constructor则必须调用super,否则就会报错。
  • 子类调用super会触发父类的constructor并将参数传递过去
  • 在super调用前子类是没有this,如果使用会报错
  • 类在继承时属性会被直接添加到实例中,方法则保留在类的原型上(跟类本身属性和方法的位置一样,类本身方法在原型上,属性在实例上,constructor中的方法和属性在实例上)
javascript 复制代码
    class F {
      constructor (sMoney) {
        this.money = 100 + sMoney
      }
      fn () {}
    }
//通过extends实现继承
    class S extends F{
//子类中显示调用constructor时必须同时调用super()方法
      constructor (money) {
        // 在super调用前子类是没有this,如果使用会报错
        //子类调用super(money)会触发父类的constructor并将参数传过去
        super(money)

      }
    }
    console.log(new S(10))
    // 类在继承时属性会被直接添加到实例中,方法则保留在类的原型上
    console.log(S.prototype.__proto__ === F.prototype); //true
相关推荐
吴声子夜歌12 小时前
ES6——Calss详解
javascript·es6·原型模式
吴声子夜歌1 天前
ES6——二进制数组详解
前端·ecmascript·es6
吴声子夜歌1 天前
ES6——正则的扩展详解
前端·mysql·es6
吴声子夜歌1 天前
ES6——Generator函数详解
前端·javascript·es6
吴声子夜歌1 天前
ES6——Set和Map详解
前端·javascript·es6
吴声子夜歌1 天前
ES6——异步操作和async函数详解
前端·ecmascript·es6
吴声子夜歌2 天前
ES6——数组的扩展详解
前端·javascript·es6
吴声子夜歌2 天前
ES6——Iterator和for...of循环详解
前端·javascript·es6
吴声子夜歌2 天前
ES6——Symbol详解
开发语言·javascript·es6
来一颗砂糖橘4 天前
吃透 ES6 扩展运算符(...):从表面语法到底层逻辑,避开所有坑
前端·javascript·es6·扩展运算符·前端进阶