浅谈ES6中的Class

转载地址:https://www.cnblogs.com/sghy/p/8005857.html

一、定义类(ES6的类,完全可以看做是构造函数的另一种写法)

复制代码
class Greet {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sayHello() {
        console.log(this.x + " " + this.y)
    }
}
let a = new Greet("hello", "everybody");
a.sayHello() //hello everybody
复制代码

《注》:

  • 以上定义的类如果用ES5的构造函数实现如下:
复制代码
function Greet(x, y) {
    this.x = x;
    this.y = y;
    this.sayHello = function () {
        console.log(this.x + " " + this.y)
    }
}

let a = new Greet("hello", "everybody");
a.sayHello() //hello everybody
复制代码
  • 类的数据类型就是函数,类本身就指向构造函数
typeof Greet; //function
Greet === Greet.prototype.constructor //true
  • 类的所有方法都定义在类的prototype属性上面
复制代码
class Greet {
    constructor() {...}
    sayHello() {...}
    sayHi(){...}
}
等同于
Greet
Greet.prototype = {
  constructor() {},
  sayHello() {},
  sayHi() {},
};
复制代码
constructor方法
  • 是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
class Greet {
}
// 等同于
class Greet {
  constructor() {}
}
  • constructor方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
复制代码
class Foo {
  constructor() {
    return Object.create(null);
  }
}

new Foo() instanceof Foo
// false
复制代码

类的实例对象:

  • 实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)。
复制代码
class Greet {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    sayHello() {
        console.log(this.x + " " + this.y)
    }
}
let a = new Greet("hello", "everybody");
// x,y都是实例对象a自身的属性,因为定义在this上
a.hasOwnProperty('x') // true
a.hasOwnProperty('y') // true
//sayHello是原型对象的属性,因为定义在Greet上
a.hasOwnProperty('sayHello') // false
a.__proto__.hasOwnProperty('sayHello') // true
复制代码
  • 类的所有实例共享一个原型对象
let a = new Greet("hello", "everybody");
let b = new Greet("hello", "everybody");

a.__proto__ === b.__proto__  //true

Class表达式:

复制代码
const MyClass = class Me {
  getClassName() {
    return Me.name;
  }
};   //类的名字是MyClass而不是Me,Me只在 Class 的内部代码可用,指代当前类。
//如果类的内部没用到的话,可以省略Me
const MyClass = class { 
    ...
 };
复制代码

不存在变量提升:必须先定义类,再使用

私有方法:

  • 利用Symbol值的唯一性
复制代码
const bar = Symbol('bar');
const snaf = Symbol('snaf');

export default class myClass{

  // 公有方法
  foo(baz) {
    this[bar](baz);
  }

  // 私有方法
  [bar](baz) {
    return this[snaf] = baz;
  }

  // ...
};
复制代码
  • 利用#标识:
复制代码
class Greet {
    constructor(x, y) {
        this.x = x;
        this.y = y;
    }
    #sayHello() {
        console.log(this.x + " " + this.y)
    }
}
复制代码

Class 的取值函数(getter)和存值函数(setter):在“类”的内部可以使用getset关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

复制代码
class MyClass {
  constructor() {
    // ...
  }
  get prop() {
    return 'getter';
  }
  set prop(value) {
    console.log('setter: '+value);
  }
}

let inst = new MyClass();

inst.prop = 123;
// setter: 123

inst.prop
// 'getter'
复制代码

Class 的静态方法:加上static关键字,表示该方法不会被实例继承,而是直接通过类来调用

复制代码
class Foo {
  static classMethod() {
    return 'hello';
  }
}

Foo.classMethod() // 'hello'

var foo = new Foo();
foo.classMethod()
// TypeError: foo.classMethod is not a function
复制代码
  • 如果静态方法包含this关键字,这个this指的是类,而不是实例
  • 父类的静态方法,可以被子类继承
  • 静态方法也是可以从super对象上调用的

Class 的静态属性和实例属性

  • 静态属性指的是 Class 本身的属性,即Class.propName,而不是定义在实例对象(this)上的属性,定义方法如下:
复制代码
class MyClass {
  static myStaticProp = 42;

  constructor() {
    console.log(MyClass.myStaticProp); // 42
  }
}
复制代码
  • 类的实例属性可以用等式,写入类的定义之中
复制代码
class MyClass {
  myProp = 42;

  constructor() {
    console.log(this.myProp); // 42
  }
}
复制代码

new.target 属性:如果构造函数不是通过new命令调用的,new.target会返回undefined

用来确定构造函数是怎么调用的。

复制代码
function Person(name) {
  if (new.target !== undefined) {
    this.name = name;
  } else {
    throw new Error('必须使用 new 命令生成实例');
  }
}
复制代码

二、Class继承:通过extends关键字实现继承

class Point {
}

class ColorPoint extends Point {
}

supper:

  • 子类必须在constructor方法中调用super方法(子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工)
复制代码
class Point { /* ... */ }

class ColorPoint extends Point {
  constructor() {
  }
}

let cp = new ColorPoint(); // ReferenceError
复制代码
  • 如果子类没有定义constructor方法,这个方法会被默认添加
复制代码
class ColorPoint extends Point {
}

// 等同于
class ColorPoint extends Point {
  constructor(...args) {
    super(...args);
  }
}
复制代码
  • 在子类的构造函数中,只有调用super之后,才可以使用this关键字(子类实例的构建,是基于对父类实例加工,只有super方法才能返回父类实例)
复制代码
class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
}

class ColorPoint extends Point {
  constructor(x, y, color) {
    this.color = color; // ReferenceError
    super(x, y);
    this.color = color; // 正确
  }
}
复制代码
  • super作为函数调用时,代表父类的构造函数。ES6 要求,子类的构造函数必须执行一次super函数。且只能用在子类的构造函数之中,用在其他地方就会报错
复制代码
class A {}

class B extends A {
  constructor() {
    super();
  }
}  //super虽然代表了父类A的构造函数,但是返回的是子类B的实例
复制代码
  • super作为对象时,在普通方法中,指向父类的原型对象;在静态方法中,指向父类。

          a)普通方法中:

复制代码
class A {
  p() {
    return 2;
  }
}

class B extends A {
  constructor() {
    super();
    console.log(super.p()); // 2
  }
}  //指向父类的原型对象

let b = new B();
复制代码

b) 静态方法中:

复制代码
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
复制代码
posted @ 2020-04-17 14:56  大熊丨rapper  阅读(173)  评论(0编辑  收藏  举报