欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6看完必会第十章------ Class 类 (可私信解惑,不会来捶我)

程序员文章站 2022-07-16 22:11:55
...

class 声明

JavaScript语言的传统方法是通过构造函数,定义并生成新对象。

ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

基本上,ES6 的class可以看作只是一个语法糖(指计算机语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用。通常来说使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。),它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。

Class不存在变量提升(hoist),这一点与ES5完全不同。

使用class关键字创建一个类代码如下:

class Person{
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }       // 方法之间不加逗号隔开,否则报错     
  sum(){        // 方法前面不用加function
  	var sum=this.x+this.y;
    return sum
  }
}

上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,通过new命令生成对象实例时,自动调用该方法。而this关键字则代表实例对象。

构造函数的prototype属性,在ES6的“类”上面继续存在。所有的方法还是在prototype属性上。

类的方法内部如果含有 this,它默认指向类的实例。

  • 类的实例对象

生成类的实例对象的写法,与ES5完全一样,也是使用new命令。如果忘记加上new,像函数那样调用类,将会报错。

// 报错
var p= Person(2, 3);
// 正确
var p= new Person(2, 3);

与ES5一样,类的所有实例共享一个原型对象

var p1 = new Person(2,3);
var p2 = new Person(3,2);
p1.__proto__ === p2.__proto__         // true

上面代码中,p1和p2都是Person的实例,它们的原型都是Point.prototype,所以__proto__属性是相等的。

 

可以通过实例的 __proto__ 属性为Class添加方法。在上一节Person类基础上添一个名为newF方法:

class Person{

  constructor(x, y) {
    this.x = x;
    this.y = y;
  }       

  sum(){        
      var sum=this.x+this.y;
      return sum

  }

}

p1= new Person()

p1.__proto__.newF= function () { return '这里是新创建的方法' };        // 给类添加一个新方法 newF

console.log(  p1.newF() )        // 这里是新创建的方法
  • class的继承

Class之间可以通过extends关键字实现继承,这比ES5的通过修改原型链实现继承来得清晰、方便很多。

class childPerson extends Person{}

上面代码定义了一个childPerson 类,该类通过extends关键字,继承了Person类的所有属性和方法。但是由于没有部署任何代码,所以这两个类完全一样,等于复制了一个Person类。

如果继承父类后要添加自己的属性和方法,如下:

class childPerson extends Person {
  constructor(x, y, color) {
    super(x, y);         // 调用父类的constructor(x, y)
    this.color = color;
  }
  toString() {
    return this.color + ' ' + super.toString();         // 调用父类的toString()
  }
}

子类必须在constructor方法中调用super方法且必须出现在 this 之前。否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。

 

  • super关键字

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数

class A {}
class B extends A {
  constructor() {        // 构造函数
    super();    // 作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。
  }
}

上面代码中,子类B的构造函数之中的super()代表调用父类的构造函数。这是必须的,否则 JavaScript引擎会报错。

 

第二种情况,super作为对象时,指向父类的原型对象。

class B extends A {
  constructor() {
    super();
    console.log(super.p());     // 指向父类的p方法
  }
}

上面代码中,子类B当中的super.p(),就是将super当作一个对象使用。此时super相当于父类A。

这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性是无法通过super调用的。

super关键字

super这个关键字,既可以当作函数使用,也可以当作对象使用。在这两种情况下,它的用法完全不同。

第一种情况,super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数

class A {}
class B extends A {
  constructor() {        // 构造函数
    super();    // 作为函数时,super()只能用在子类的构造函数之中,用在其他地方就会报错。
  }
}

上面代码中,子类B的构造函数之中的super()代表调用父类的构造函数。这是必须的,否则 JavaScript引擎会报错。

 

第二种情况,super作为对象时,指向父类的原型对象。

class B extends A {
  constructor() {
    super();
    console.log(super.p());     // 指向父类的p方法
  }
}

上面代码中,子类B当中的super.p(),就是将super当作一个对象使用。此时super相当于父类A。

这里需要注意,由于super指向父类的原型对象,所以定义在父类实例上的方法或属性是无法通过super调用的。

  • class静态方法

类相当于实例的原型,所有在类中定义的方法都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。

class Foo {
  static classMethod() {
    return 'hello';
  }
}
Foo.classMethod()         // 'hello'           直接类调用
var foo = new Foo();      // 创建一个实例
foo.classMethod()        // 报错内容: foo.classMethod is not a function        实例调用报错

上面代码中,Foo 类的classMethod 方法前有static 关键字,表明该方法是一个静态方法,可以直接在Foo 类上调用,而不是在Foo 类的实例上调用。如果在实例上调用静态方法,会抛出一个错误,表示不存在该方法。

父类的静态方法,可以被子类继承。静态方法也是可以从super对象上调用的。

 

第十一章:ES6看完必会第十一章------ Map和Set数据结构 (可私信解惑,不会来捶我)

相关标签: ES6快速入门 ES6