class
借鉴于网上
定义类
类声明
定义一个类的方法是使用一个类声明 ,可以用calss关键字来声明,但是使用类声明与函数声明不一样的是,类声明不会发生声明提升
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
类表达式
定义类的另一种方式是类表达式,也可以匿名或具名,且一个具名表达式的名称是类内的一个局部属性,它可以通过类本身(不是类实例)的name属性来获取。
// 匿名类
let Rectangle = class {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// output: "Rectangle"
// 具名类
let Rectangle = class Rectangle2 {
constructor(height, width) {
this.height = height;
this.width = width;
}
};
console.log(Rectangle.name);
// 输出: "Rectangle2"
类体的方法和定义
1、严格模式
类声明和类表达式的主体都执行在严格模式下
2、构造函数
constructor方法用于创建和初始化一个由class创建的对象
3、原型方法
class Rectangle {
// constructor
constructor(height, width) {
this.height = height;
this.width = width;
}
// Getter
get area() {
return this.calcArea()
}
// Method
calcArea() {
return this.height * this.width;
}
}
const square = new Rectangle(10, 10);
console.log(square.area); // 100
4、静态方法
调用静态方法不用实例化该类,但不能通过一个类实例来调用静态方法。
静态方法常用于为一个应用程序创建创建工具函数
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static distance(a, b) {//static用来定义一个类的一个静态方法
const dx = a.x - b.x;
const dy = a.y - b.y;
return Math.hypot(dx, dy);
}
}
const p1 = new Point(5, 5);
const p2 = new Point(10, 10);
console.log(Point.distance(p1, p2));
5、用原型和静态方法包装
当调用原型或者静态方法时,没有指定this的值,那么方法内的值将会被指定为undefined。即使是你未设置‘use strict’,因为class内部的代码总是在严格模式下执行的。
class Animal {
speak() {
return this;
}
static eat() {
return this;
}
}
let obj = new Animal();
obj.speak(); // Animal {} 指定this的值为obj
let speak = obj.speak;
speak(); // undefined 没有指定this的值
Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined 没有指定this的值
严格模式下,this值不会装箱,将会保留传入状态
function Animal() { }
Animal.prototype.speak = function() {
return this;
}
Animal.eat = function() {
return this;
}
let obj = new Animal();
let speak = obj.speak;
speak(); // global object
let eat = Animal.eat;
eat(); // global object
6、实例属性
1、实例的属性必须定义在类的方法里
class Rectangle {
constructor(height, width) {
this.height = height;
this.width = width;
}
}
2、静态或原型的数据属性必须定义在类的方法外面
Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;
7、字段声明
1、公有字段声明
使用JavaScript字段声明语法,上面的示例可以写成:
class Rectangle {
height = 0;
width;
constructor(height, width) {
this.height = height;
this.width = width;
}
}
2、私有字段声明
class Rectangle {
#height = 0;
#width;
constructor(height, width) {
this.#height = height;
this.#width = width;
}
}
从类外部引用私有字段是错误的。它们只能在类里面中读取或写入。通过定义在类外部不可见的内容,可以确保类的用户不会依赖于内部,因为内部可能在不同版本之间发生变化
私有字段不能通过在之后的赋值来创建它们,这种方式只适用于普通属性
使用extends创建子类
extends 关键字在 类声明 或 类表达式 中用于创建一个类作为另一个类的一个子类。
class Animal {
constructor(name) {
this.name = name;
}
speak() {
console.log(`${this.name} makes a noise.`);
}
}
class Dog extends Animal {
constructor(name) {
super(name); // 调用超类构造函数并传入name参数
}
speak() {
console.log(`${this.name} barks.`);
}
}
var d = new Dog('Mitzie');
d.speak();// 'Mitzie barks.'
如果子类中定义了构造函数,那么它必须先调用 super() 才能使用 this 。
也可以继承传统的基于函数的“类”:
function Animal (name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(this.name + ' makes a noise.');
}
class Dog extends Animal {
speak() {
super.speak();
console.log(this.name + ' barks.');
}
}
var d = new Dog('Mitzie');
d.speak();//Mitzie makes a noise. Mitzie barks.
请注意,类不能继承常规对象(不可构造的)。如果要继承常规对象,可以改用Object.setPrototypeOf():
var Animal = {
speak() {
console.log(this.name + ' makes a noise.');
}
};
class Dog {
constructor(name) {
this.name = name;
}
}
Object.setPrototypeOf(Dog.prototype, Animal);// 如果不这样做,在调用speak时会返回TypeError
var d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.
species
你可能希望在派生数组类MyArray中返回Array对象。这种species方式允许你覆盖默认的构造函数
例如:当使用象map()返回默认构造函数的方法时,你希望这些方法返回一个父Array对象,而不是MyArray对象。Symbol.species符号可以让你这样做:
class MyArray extends Array {
// Overwrite species to the parent Array constructor
static get [Symbol.species]() { return Array; }
}
var a = new MyArray(1,2,3);
var mapped = a.map(x => x * x);
console.log(mapped instanceof MyArray);
// false
console.log(mapped instanceof Array);
// true
使用super调用超类
super用于调用对象的父对象上的函数
super关键字,它指代父类的实例(即父类的this对象)。子类必须在constructor中调用super方法,否则新建实例时会报错。这是因为子类没有自己的this对象,而是继承父类的this对象,然后对其进行加工。如果不调用super方法,子类就得不到this对象。
class Cat {
constructor(name) {
this.name = name;
}
speak() {
console.log(this.name + ' makes a noise.');
}
}
class Lion extends Cat {
speak() {
super.speak();
console.log(this.name + ' roars.');
}
}
Mix-ins
抽象子类或者 mix-ins 是类的模板。 一个 ECMAScript 类只能有一个单超类,所以想要从工具类来多重继承的行为是不可能的。子类继承的只能是父类提供的功能性。因此,例如,从工具类的多重继承是不可能的。该功能必须由超类提供。
一个以超类作为输入的函数和一个继承该超类的子类作为输出可以用于在ECMAScript中实现混合:
var calculatorMixin = Base => class extends Base {
calc() { }
};
var randomizerMixin = Base => class extends Base {
randomize() { }
};
使用 mix-ins 的类可以像下面这样写:
class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }