Es6 - class类

113 阅读3分钟

1、简介

定义Class类

class Point {
  _count = 0; // 实例属性(新写法)
  constructor(x, y) {
    // 实例属性、方法
    this.x = x;
    this.y = y;
  }
  toString() {
    // 原型上的方法
    return "(" + this.x + ", " + this.y + ")";
  }
}

var point = new Point(2, 3);
point.toString(); // (2, 3)
point.hasOwnProperty("x"); // true  x是实例上的属性
point.hasOwnProperty("y"); // true  y是实例上的属性
point.hasOwnProperty("toString"); // false 方法不是实例上的
point.__proto__.hasOwnProperty("toString"); // true  方法是原型上的

改变原型方法的this指向

class Person {
  constructor() {
    // 构造函数的属性和方法
    this.name = "zhangsan";
    this.showName = this.showName.bind(this);
  }
  showName() {
    // 原型上方法:this默认指向实例
    return `名字为${this.name}`;
  }
}

let p1 = new Person();

// 1、如果结构数来,默认指向全局
// 2、由于bind改变this指向,从新指向实例
let { showName } = p1; // 脱离了上下文
console.log(showName());

2、constructor ( 构造函数 )

  • constructor 是默认方法,new对象实时,自动调用
  • constructor 默认返回实例对象(即this),可以指定返回另外一个对象
class Foo {
  constructor() {
    // 默认返回实例对象,可手动指定对象
    return Object.create(null);
  }
}
new Foo() instanceof Foo;
// false

3、静态属性和方法

静态属性:

  • Class 本身的属性,即Class.prop
  • 不是定义在实例对象(this)上的属性
class MyClass {
  static myStaticProp = 42;
  constructor() {
    console.log(MyClass.myStaticProp); // 42
  }
}

class IncreasingCounter {
  _count = 0;
  get value() {
    return this._count;
  }
  increment() {
    this._count++;
  }
}

静态方法:

  • 不会被实例继承,直接通过类来调用
  • 如果静态方法包含this关键字,这个this指的是类,而不是实例
  • 父类的静态方法,可以被子类继承
//不会被实例继承,直接通过类来调用
class Foo {
  static classMethod() {
    return "hello";
  }
}
Foo.classMethod(); // 'hello'

var foo = new Foo();
foo.classMethod();

//如果静态方法包含this关键字,这个this指的是类,而不是实例
class Foo {
  // 静态方法中的this,指向类并非实例
  static bar() {
    this.baz();
  }
  static baz() {
    console.log("hello");
  }
  baz() {
    console.log("world");
  }
}
Foo.bar(); // hello

// 父类的静态方法,可以被子类继承
class Foo {
  static classMethod() {
    return "hello";
  }
}

class Bar extends Foo {
  static classMethod() {
    return super.classMethod() + ", too";
  }
}

Bar.classMethod(); // "hello, too"

4、继承(extend、super)

第一种情况:super作为函数调用时( 返回B的实例 )

  • 代表父类A的构造函数,返回的是子类B的实例
  • 内部的this指向的是B:相当于执行 A.prototype.constructor.call(this)
class A {
  constructor() {
    this.age = 18;
    this.name = "张三";
    this.getName = function () {
      return this.name;
    };
  }
  getAge() {
    return this.age;
  }
}

class B extends A {
  constructor() {
    // 相当于构造函数继承
    super(); // A.prototype.constructor.call(this)
  }
}
let a = new A();
let b = new B();
console.log(a.getName());
console.log(a.getAge());

// super对某个属性赋值,这时super就是this
// 赋值的属性会变成子类实例的属性
class A {
  constructor() {
    this.x = 1;
  }
}
class B extends A {
  constructor() {
    super();
    this.x = 2;
    super.x = 3; //实质为B添加属性
    console.log(super.x); // undefined
    console.log(this.x); // 3
  }
}
let b = new B();

第二种情况:super作为对象时

  • 普通方法中:super 指向父类原型对象
    • super.p()就相当于A.prototype.p()
    • 定义在父类实例上的方法或属性,是无法通过super调用
  • 静态方法中指向父类( 构造函数 )
    • super将指向父类,而不是父类的原型对象
    • 调用父类的方法时,内部的this指向当前的子类,而不是子类的实例
//普通方法中:super指向 A.prototype
class A {
  constructor() {
    this.p = 2;
  }
}
class B extends A {
  get m() {
    // 普通方法中 super 指向父类原型对象
    return super.p;
  }
}
let b = new B();
b.m; // undefined

//用在静态方法之中,这时super将指向父类
class Parent {
  static myMethod(msg) {
    console.log("static", msg);
  }
  myMethod(msg) {
    console.log("instance", msg);
  }
}
class Child extends Parent {
  static myMethod(msg) {
    super.myMethod(msg); //指向父类
  }
  myMethod(msg) {
    super.myMethod(msg); //指向父类原型
  }
}
//调用类方法
Child.myMethod(1); // static 1
//调用原型上的方法
var child = new Child();
child.myMethod(2); // instance 2