跳转到内容

JavaScript/OOP-类

来自维基教科书,开放的书籍,为开放的世界



面向对象编程中基于类的编程语言的流行程度激励了 JavaScript 社区,他们用模仿基于类的编程方法的语法来覆盖其基于原型的 OOP 实现。EcmaScript 2015 (ES6) 通过相应的关键词(如“class”或“extend”)得到了扩展。

类是用于创建对象的模板或“蓝图”。它们封装了它们的数据,并包含用于处理数据的函数。

class Person {
  // Class body is always implicitly in "use strict" mode
  constructor(name) {
    // Data. Declarations like 'let x = 0' are not necessary.
    this.name = name;
  }
  // functionality
  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
alert(ada.showName());

关键字 class 引入类定义。在示例中,Person 是类名。它后面跟着用花括号 { }(第 1 行到第 11 行)括起来的类主体。在主体内部,有一个特殊方法 constructor。此函数在类创建期间被调用。在示例中,它接受一个参数,即一个人的姓名。在 constructor 内部,此参数使用关键字“this”在内部存储。该类只提供一个功能:showName 方法。

静态属性和方法

[编辑 | 编辑源代码]

上面的语法显示了如何处理单个对象(实例 - 就像上面示例中的“ada”)的属性和方法。还可以定义在单个对象级别不可用但在类级别可用的属性和方法 - 上述示例中的“Person”。它们由关键字 static 引入。

class Person {
  constructor(name) {
    // data
    this.name = name;
  }

  static className = "The PERSON Class";
  static showClassName() {return "The name of this class is: " + this.className};

  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
// alert(ada.showClassName()); // Error!
alert(Person.showClassName());

第 7 行和第 8 行使用“static”关键字。因此,属性和方法不适用于实例,而只适用于整个类。

类方法可以作为属性提供。这使程序员能够区分通过圆括号 () 访问方法和属性。关键字 get 引入此功能。

class Person {
  constructor(name) {
    this.name = name;
  }
  // getter
  get showTheName() {
    return this.showName();
  }
  // 'regular' method
  showName() {
    return "My name is: " + this.name;
  }
}

const ada = new Person("Lovelace");
// NO parenthesis ()
alert(ada.showTheName);

接下来,我们定义一个类层次结构。这是使用关键字 extends 完成的。在示例中,EmployeePerson 的子类,并且可以访问其所有属性和方法。

class Person {
  constructor(name) {
    this.name = name;
  }
  // method
  showName() {
    return "My name is: " + this.name;
  }
}
class Employee extends Person {
  constructor(name, company) {
    super(name);
    this.company = company;
  }
  // method
  showCompany() {
    return "I, " + this.name + ", work at the company " + this.company;
  }
}

const henry = new Employee("Henry Miller", "ACME Inc.");
alert(henry.showCompany());
alert(henry.showName());     // method of the parent class

第 12 行调用父类的构造函数。这是必要的,因为父类的 constructor 创建“this”。

访问控制

[编辑 | 编辑源代码]

默认情况下,类属性和方法是可访问的。您可以使用井号 # 作为它们名称的第一个字符来隐藏它们。

class Person {

  // two hidden properties (sometimes called 'private fields')
  #firstName;
  #lastName;

  constructor(firstName, lastName) {
    this.#firstName = firstName;
    this.#lastName = lastName;
    // one public property
    this.name = lastName + ", " + firstName;
  }
  #showName() {  // hidden method
    alert("My name is " + this.name);
  }
}

const ada = new Person("Ada", "Lovelace");
alert(ada.name);        // ok
alert(ada.firstName);   // undefined
alert(ada.#firstName);  // undeclared private field

alert(ada.#showName()); // undeclared private method

多态性

[编辑 | 编辑源代码]

如果方法名在“父”类和“子”类中都被使用,JavaScript 引擎将调用相关类的那个方法。

class Person {
  constructor(name) {
    this.name = name;
  }
  // method name is used also in 'child'
  showName() {
    return "My name is: " + this.name;
  }
}
class Employee extends Person {
  constructor(name, company) {
    super(name);
    this.company = company;
  }
  // same method name as in 'parent'
  showName() {
    return "My name is: " + this.name + ". I'm working at the company " + this.company;
  }
}

const henry = new Employee("Henry Miller", "ACME Inc.");
alert(henry.showName());       // from Employee

const nextPerson = new Person("John");
alert(nextPerson.showName());  // from Person

示例定义并使用两个不同的方法 showName

this 不是变量或对象;它是一个关键字。根据上下文,它指的是不同的东西。在类定义的上下文中,它指的是类本身,例如,this.city = "Nairobi" 指的是当前类的属性“city”。

this 在文件的最顶层使用时(换句话说,在任何函数或对象之外),它指的是全局对象。在严格模式下,在函数中,this 为 undefined。在 DOM 事件中,它指的是接收事件的元素。

… 在另一个页面上提供(点击此处)。
华夏公益教科书