ja类主体和方法定义

类主体和方法定义

类的主体是放在大括号中的部分{}在这里定义类成员,例如方法或构造函数。

严格模式

类的主体以严格模式执行,即,此处编写的代码将采用更严格的语法以提高性能,否则将抛出一些其他的静默错误,并且某些关键字保留给将来的ECMAScript版本。

建设者

constructor方法是用于创建和初始化使用创建的对象的特殊方法class在一个类中,只能有一个名为“ constructor”的特殊方法。SyntaxError如果该类包含一个以上的constructor方法实例,则将引发A。

构造函数可以使用super关键字来调用超类的构造函数。

原型方法

另请参见方法定义

class Rectangle {
  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

静态方法

static关键字定义为一类的静态方法。静态方法被称为没有实例化的类并不能通过类实例调用。静态方法通常用于为应用程序创建实用程序功能。

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

  static distance(a, b) {
    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);
p1.distance; //undefined
p2.distance; //undefined

console.log(Point.distance(p1, p2)); // 7.0710678118654755

this与原型和静态方法绑定

当调用静态或原型方法而没有for的值时  this,例如通过将变量分配给该方法然后调用它,则该this值将undefined在方法内部。即使"use strict"指令不存在,此行为也将是相同的,因为class主体的语法边界内的代码始终以严格模式执行。

class Animal { 
  speak() {
    return this;
  }
  static eat() {
    return this;
  }
}

let obj = new Animal();
obj.speak(); // the Animal object
let speak = obj.speak;
speak(); // undefined

Animal.eat() // class Animal
let eat = Animal.eat;
eat(); // undefined

如果我们在非严格模式下使用传统的基于函数的语法重写以上内容,则this方法调用将自动绑定到初始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 (in non–strict mode)

let eat = Animal.eat;
eat(); // global object (in non-strict mode)

实例属性

实例属性必须在类方法内定义:

class Rectangle {
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}

静态(类方面)数据属性和原型数据属性必须在ClassBody声明之外定义:

Rectangle.staticWidth = 20;
Rectangle.prototype.prototypeWidth = 25;

现场申报

公共和私有字段声明是JavaScript标准委员会TC39提出实验性功能(第3阶段)对浏览器的支持是有限的,但是可以通过构建步骤(如Babel)使用该功能

公共领域声明

使用JavaScript字段声明语法,上面的示例可以写成:

class Rectangle {
  height = 0;
  width;
  constructor(height, width) {    
    this.height = height;
    this.width = width;
  }
}

通过预先声明字段,类定义变得更加自我记录,并且字段始终存在。

如上所示,可以使用默认值或不使用默认值来声明字段。

有关更多信息,请参见公共类字段

私人领域声明

使用私有字段,可以按以下方式细化定义。

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); // call the super class constructor and pass in the name parameter
  }

  speak() {
    console.log(`${this.name} barks.`);
  }
}

let 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() {
    console.log(`${this.name} barks.`);
  }
}

let d = new Dog('Mitzie');
d.speak(); // Mitzie barks.

// For similar methods, the child's method takes precedence over parent's method

请注意,类不能扩展常规(不可构造)对象。如果要从常规对象继承,则可以使用Object.setPrototypeOf()

const Animal = {
  speak() {
    console.log(`${this.name} makes a noise.`);
  }
};

class Dog {
  constructor(name) {
    this.name = name;
  }
}

// If you do not do this you will get a TypeError when you invoke speak
Object.setPrototypeOf(Dog.prototype, Animal);

let d = new Dog('Mitzie');
d.speak(); // Mitzie makes a noise.

种类

您可能要返回Array派生数组类中的对象MyArray种类模式可让您覆盖默认构造函数。

例如,当使用诸如这样的方法map()返回默认构造函数时,您希望这些方法返回父Array对象而不是MyArray对象。Symbol.species符号使您可以执行此操作:

class MyArray extends Array {
  // Overwrite species to the parent Array constructor
  static get [Symbol.species]() { return Array; }
}

let a = new MyArray(1,2,3);
let mapped = a.map(x => x * x);

console.log(mapped instanceof MyArray); // false
console.log(mapped instanceof Array);   // true

超级班级通话 super

super关键字用来调用父类的相应方法。与基于原型的继承相比,这是一个优势。

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.`);
  }
}

let l = new Lion('Fuzzy');
l.speak(); 
// Fuzzy makes a noise.
// Fuzzy roars.

混入

抽象子类或混入是类的模板。ECMAScript类只能有一个超类,因此,例如,无法从工具类进行多重继承。该功能必须由超类提供。

具有超类作为输入和扩展该超类作为输出的子类的函数可用于在ECMAScript中实现混入:

let calculatorMixin = Base => class extends Base {
  calc() { }
};

let randomizerMixin = Base => class extends Base {
  randomize() { }
};

然后,可以使用以下方式编写使用这些混入的类:

class Foo { }
class Bar extends calculatorMixin(randomizerMixin(Foo)) { }

 

posted @ 2020-09-02 16:51  jamyes2020  阅读(244)  评论(0编辑  收藏  举报