Bootstrap

彻底理解 javascript 类的静态属性和静态方法

静态属性和静态方法不是独立的东西,需要放在Javascript 类 这个框架下去理解。一下分10步介绍:

步骤一:了解类的概念

JavaScript 中的类是一种对象构造函数的特殊形式,它允许你创建具有相似属性和方法的多个对象实例。类是面向对象编程的基本概念之一。

在 JavaScript 中,类可以通过关键字 class 来定义,并使用 new 关键字来实例化对象。

下面是一个类的基本结构示例:

class MyClass {
  constructor() {
    // 构造函数
  }

  method1() {
    // 方法1
  }

  method2() {
    // 方法2
  }
}

在这个示例中,MyClass 是一个类名,constructor 是一个特殊的方法,用于在创建对象时初始化对象的属性。method1method2 是类的方法。

步骤二:创建类的实例

在 JavaScript 中,通过使用 new 关键字,可以实例化一个类,并创建类的对象。实例化类意味着创建一个类的具体实例,该实例拥有类定义中定义的属性和方法。

要创建一个类的实例,可以按照以下方式操作:

const myObject = new MyClass();

在这个示例中,MyClass 是我们在步骤一中定义的类名。通过调用 new 关键字和类名,可以创建一个名为 myObject 的对象实例。

现在,myObject 对象将具有 MyClass 类定义中定义的所有属性和方法。

你可以创建多个类的实例,每个实例都是独立的,并且可以根据需要访问和操作它们的属性和方法。

步骤三:定义和使用类的属性

类的属性是与类实例相关联的值。这些值可以通过类的构造函数进行初始化,并在类的方法中使用和修改。

在 JavaScript 类中,可以在构造函数中定义属性,并使用 this 关键字将值分配给属性。this 关键字引用了当前类的实例。

以下是一个示例,展示了如何定义和使用类的属性:

class MyClass {
  constructor() {
    this.myProperty = 10;
  }

  myMethod() {
    console.log(this.myProperty);
  }
}

const myObject = new MyClass();
myObject.myMethod(); // 输出:10

在这个示例中,我们在 MyClass 的构造函数中定义了一个名为 myProperty 的属性,并将其初始化为 10。然后,在 myMethod 方法中,我们使用 console.log 打印了该属性的值。

当创建 MyClass 的实例 myObject 后,我们可以调用 myObject.myMethod() 来访问和使用 myProperty 属性。

通过构造函数,你可以初始化类的属性,并在类的其他方法中使用和修改这些属性。

步骤四:定义和调用类的方法

类的方法是类中定义的函数,用于执行特定的操作和功能。可以通过类的实例来调用这些方法。

在 JavaScript 类中,可以在类的定义中定义方法,并在需要时通过类的实例来调用它们。方法可以访问类的属性和其他方法。

以下是一个示例,展示了如何定义和调用类的方法:

class MyClass {
  constructor() {
    this.myProperty = 10;
  }

  myMethod() {
    console.log('Hello from myMethod');
    console.log('Property value:', this.myProperty);
  }
}

const myObject = new MyClass();
myObject.myMethod();

在这个示例中,我们定义了一个名为 myMethod 的方法。在方法中,我们打印了一条简单的消息,并访问了类的属性 myProperty 的值。

创建 MyClass 的实例 myObject 后,我们通过 myObject.myMethod() 调用了 myMethod 方法,并得到了相应的输出。

你可以根据需要在类中定义多个方法,以执行不同的功能和操作。方法可以访问类的属性,并在方法内部使用它们。

步骤五:使用构造函数传递参数初始化属性

在步骤三中,我们在构造函数中初始化了类的属性。然而,有时我们可能希望在创建类的实例时,通过传递参数来自定义属性的初始值。

在 JavaScript 类中,可以通过构造函数的参数来接收外部传递的值,并将这些值分配给类的属性。

以下是一个示例,展示了如何使用构造函数传递参数来初始化属性:

class MyClass {
  constructor(initialValue) {
    this.myProperty = initialValue;
  }

  myMethod() {
    console.log('Property value:', this.myProperty);
  }
}

const myObject = new MyClass(20);
myObject.myMethod(); // 输出:20

在这个示例中,我们修改了 MyClass 的构造函数,使其接受一个参数 initialValue。在构造函数中,我们将传递的值分配给类的属性 myProperty

创建 MyClass 的实例 myObject 时,我们传递了参数值 20,这样就自定义了 myProperty 的初始值。

当调用 myObject.myMethod() 时,我们可以看到属性 myProperty 的值被正确地设置为传递的初始值。

通过使用构造函数传递参数,你可以在创建类的实例时,根据需要自定义属性的初始值。

步骤六:定义和使用静态方法

在 JavaScript 类中,除了实例方法,还可以定义静态方法。静态方法是直接与类本身相关联的方法,而不是与类的实例相关联。静态方法可以在类的实例化之前直接调用。

在类中定义静态方法时,需要使用 static 关键字。这样定义的方法将直接绑定到类本身,而不是类的实例。

以下是一个示例,展示了如何定义和使用静态方法:

class MyClass {
  constructor() {
    // 构造函数
  }

  static myStaticMethod() {
    console.log('This is a static method');
  }
}

MyClass.myStaticMethod(); // 输出:This is a static method

在这个示例中,我们在 MyClass 中定义了一个静态方法 myStaticMethod。静态方法使用 static 关键字进行定义。

与实例方法不同,我们不需要创建类的实例就可以直接调用静态方法。通过 MyClass.myStaticMethod(),我们可以直接调用静态方法,并得到相应的输出。

需要注意的是,静态方法无法访问类的实例属性,因为它们与类的实例无关。它们主要用于执行与类相关的操作,而不是与特定实例相关的操作。

静态方法在以下场景下非常有用:

  1. 实用工具函数:静态方法可以用于实现实用工具函数,这些函数与类的实例无关,通常用于执行一些常用的功能操作。例如,Math 对象中的 Math.max() 方法就是一个静态方法,它用于返回一组数字中的最大值。
class MathUtils {
  static getMax(...numbers) {
    return Math.max(...numbers);
  }
}

console.log(MathUtils.getMax(10, 5, 8)); // 输出:10
console.log(MathUtils.getMax(1, 3, 2)); // 输出:3

在这个示例中,我们定义了一个 MathUtils 类,其中有一个静态方法 getMax(),用于返回传入数字中的最大值。由于这个方法与类的实例无关,我们可以直接通过类名调用它。

  1. 工厂模式:静态方法常用于实现工厂模式,用于创建和返回类的实例。工厂方法是一种创建对象的设计模式,它可以封装实例化对象的逻辑并返回所需的对象。通过静态方法实现工厂模式可以使代码更加清晰和可维护。
class Car {
  constructor(make, model) {
    this.make = make;
    this.model = model;
  }

  static createCar(make, model) {
    return new Car(make, model);
  }
}

const myCar = Car.createCar('Toyota', 'Camry');
console.log(myCar.make); // 输出:Toyota
console.log(myCar.model); // 输出:Camry

在这个示例中,我们定义了一个 Car 类,其中有一个静态方法 createCar(),它接受制造商和型号作为参数,并返回一个新的 Car 实例。通过调用静态方法 createCar(),我们可以创建一个 Car 对象,而不需要直接调用构造函数。

这些场景只是静态方法的一些示例,实际上,静态方法可以在许多其他情况下使用,根据具体需求和设计模式来决定是否使用静态方法。

步骤七:定义和使用静态属性

除了静态方法之外,JavaScript 类还支持静态属性。静态属性是直接与类本身相关联的属性,而不是与类的实例相关联。它们可以在类的定义中直接访问和修改。

要定义静态属性,可以使用类的构造函数或类本身来声明并初始化它们。静态属性是类级别的,对于所有类的实例都是共享的。

以下是一个示例,展示了如何定义和使用静态属性:

class MyClass {
  static staticProperty = 'This is a static property';

  static staticMethod() {
    console.log('This is a static method');
  }
}

console.log(MyClass.staticProperty); // 输出:This is a static property
MyClass.staticMethod(); // 输出:This is a static method

在这个示例中,我们使用 static 关键字定义了一个静态属性 staticProperty,并将其初始化为字符串 'This is a static property'。静态属性可以直接通过类名访问。

同样地,我们也可以使用 static 关键字定义静态方法 staticMethod,并在其中添加相应的逻辑。静态方法也可以直接通过类名调用。

通过定义和使用静态属性,我们可以在类级别上存储和访问共享的数据,并在静态方法中执行与类相关的操作。

静态属性是类级别的,对于所有类的实例都是共享的

当我们说静态属性是类级别的,意味着它们与类本身直接相关,而不是与类的实例相关。在类中定义的静态属性不会被每个类的实例所拥有,而是在类的级别上共享。

这意味着,无论创建多少个类的实例,它们都共享相同的静态属性。当我们修改静态属性时,这个修改将反映在所有类的实例中。

例如,假设我们有一个名为 MyClass 的类,并定义了一个静态属性 staticProperty

class MyClass {
  static staticProperty = 'This is a static property';
}

当我们创建多个 MyClass 的实例时,它们之间并没有各自独立的 staticProperty 值。相反,它们共享相同的静态属性值:

const instance1 = new MyClass();
const instance2 = new MyClass();

console.log(instance1.staticProperty); // 输出:This is a static property
console.log(instance2.staticProperty); // 输出:This is a static property

在这个示例中,无论是 instance1 还是 instance2,它们都访问的是同一个静态属性 staticProperty 的值。这是因为静态属性在类级别上被共享,而不是在每个实例中分别存在。

这种共享的特性使得静态属性非常适合存储对于整个类而言是公共的数据或配置。

步骤八:定义和使用访问器(getter)和设置器(setter)

在 JavaScript 类中,你可以使用访问器(getter)和设置器(setter)来控制对类的属性的访问和设置。访问器允许你获取属性的值,设置器允许你设置属性的值。

访问器和设置器是一对方法,用于定义属性的读取和写入操作。它们提供了更好的封装性和灵活性,以便在获取和设置属性时执行额外的逻辑。

以下是一个示例,展示了如何定义和使用访问器和设置器:

class MyClass {
  constructor() {
    // 构造函数
    this._myProperty = 0; // 注意:属性名前加下划线,用于与访问器区分
  }

  get myProperty() {
    return this._myProperty;
  }

  set myProperty(value) {
    if (value >= 0) {
      this._myProperty = value;
    } else {
      console.log('Invalid value for myProperty');
    }
  }
}

const myObject = new MyClass();
console.log(myObject.myProperty); // 输出:0

myObject.myProperty = 10;
console.log(myObject.myProperty); // 输出:10

myObject.myProperty = -5; // 输出:Invalid value for myProperty

在这个示例中,我们定义了一个名为 myProperty 的属性,以及对应的访问器和设置器。注意,在属性名前我们加了一个下划线 _,用于与访问器和设置器的名称区分。

在访问器 get myProperty() 中,我们返回属性 _myProperty 的值。这样,当我们访问 myObject.myProperty 时,实际上是在调用访问器,并获取属性的值。

在设置器 set myProperty(value) 中,我们检查传递的值是否大于等于 0。如果是,我们将值分配给属性 _myProperty。否则,我们打印一条错误消息。

通过定义访问器和设置器,我们可以在获取和设置属性时执行自定义逻辑。这使得属性的读取和写入操作更加灵活和安全。

步骤九:在类中实现继承

继承是面向对象编程中重要的概念之一,它允许你创建一个新类,该类继承了另一个已存在的类的属性和方法。在 JavaScript 中,可以使用 extends 关键字来实现类的继承。

通过继承,子类可以继承父类的属性和方法,并且可以添加自己的属性和方法,或者覆盖父类的属性和方法。

以下是一个示例,展示了如何在类中实现继承:

class ParentClass {
  parentMethod() {
    console.log('This is a parent method');
  }
}

class ChildClass extends ParentClass {
  childMethod() {
    console.log('This is a child method');
  }
}

const myObject = new ChildClass();
myObject.parentMethod(); // 输出:This is a parent method
myObject.childMethod(); // 输出:This is a child method

在这个示例中,我们定义了一个名为 ParentClass 的父类,其中包含一个 parentMethod 方法。

然后,我们定义了一个名为 ChildClass 的子类,并使用 extends 关键字将其继承自 ParentClass。在子类中,我们定义了一个名为 childMethod 的方法。

创建 ChildClass 的实例 myObject 后,我们可以调用继承自父类的 parentMethod 方法和子类自身定义的 childMethod 方法。

通过继承,子类可以重用父类的功能,并且可以扩展和定制自己的行为。

步骤十:在子类中调用父类的方法

在继承关系中,子类可以调用继承自父类的方法。这样可以重用父类的功能,并在子类中添加自己的特定行为。

在 JavaScript 中,可以使用 super 关键字来调用父类的方法。super 关键字引用了父类的构造函数和方法。

以下是一个示例,展示了如何在子类中调用父类的方法:

class ParentClass {
  parentMethod() {
    console.log('This is a parent method');
  }
}

class ChildClass extends ParentClass {
  childMethod() {
    super.parentMethod(); // 调用父类的方法
    console.log('This is a child method');
  }
}

const myObject = new ChildClass();
myObject.childMethod();

在这个示例中,我们定义了一个名为 ParentClass 的父类,其中包含一个 parentMethod 方法。

然后,我们定义了一个名为 ChildClass 的子类,它继承自 ParentClass。在子类中,我们定义了一个名为 childMethod 的方法。

childMethod 方法中,我们使用 super.parentMethod() 来调用父类的 parentMethod 方法。这样可以在子类中首先执行父类的操作,然后再添加子类特定的行为。

创建 ChildClass 的实例 myObject 后,我们调用 myObject.childMethod(),父类的方法 parentMethod 将首先被调用,然后是子类自身定义的 childMethod 方法。

通过使用 super 关键字,子类可以轻松地调用父类的方法,并在继承关系中组合功能。

;