全部 / 前端 / 技术 · 2022年7月4日 0

54 – 类:静态成员 && 55 – 扩展内置的类和对象

原文地址:https://dev.to/bhagatparwinder/class-static-members-3kl3

JavaScript 中的类可以有静态方法和属性,这些都是类的成员而不是类创建的实例对象的成员。最可能是,你将静态方法作为工具方法(比较类的实例、克隆和创建对象)。

静态方法

class Person {
    name;
    age;

    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    static orderByAge(a, b) {
        return a.age - b.age;
    }
}

const employees = [
    new Person("Parwinder", 22),
    new Person("Robert", 33),
    new Person("George", 18),
    new Person("Eliu", 101),
    new Person("Gaurav", 39)
]

employees.sort(Person.orderByAge);

console.log(employees);

上面的例子中,Person 类通过 name 和 age 创建了一个实例。在类中我们创建了一个静态方法 orderByAge,这个方法是用来比较所有的 Person 年龄的,此方法不属于任何实例而是归属于类(或创建它们的父类)。

上面代码将会输出如下:

[ 
  { name: 'George', age: 18 },
  { name: 'Parwinder', age: 22 },
  { name: 'Robert', age: 33 },
  { name: 'Gaurav', age: 39 },
  { name: 'Eliu', age: 101 } 
]

记住静态方法只属于类,你不能像下面代码的最后两行那样书写。

class Person {
    name;
    age;

    constructor(name, age) {
        this.name = name;
        this.age = age;
    }

    static orderByAge(a, b) {
        return a.age - b.age;
    }

    static sayMyName(person) {
        return person.name;
    }
}

const me = new Person("Parwinder", 101);

console.log(me.name); // Parwinder => this is valid
console.log(me.age); // 101 => this is valid
console.log(me.orderByAge); // undefined or Property 'orderByAge' is a static member of type 'Person' 🚨
console.log(me.sayMyName); // undefined or Property 'sayMyName' is a static member of type 'Person' 🚨

静态属性(或公共静态字段)

这个特性目前在 ES 提案的第三阶段(作者写作时)。

当我们想让一个字段只存在于类中而不是每个实例中时才使用静态字段,它可以被用来存储配置、端点(endpoints)、缓存等等。

class Base {
    static field = "Base Class";
}

class Child extends Base {

}

class GrandChild extends Child {
    static field = "Grand Child Class";
}

console.log(Base.field); // Base Class
console.log(Child.field); // Base Class
console.log(GrandChild.field); // Grand Child Class

你可能想扩展 JavaScript 内置对象或类提供的功能,或者是一些目前还没有被 JavaScript 支持的数组或字符串的方法,但你的项目中经常要用到。典型地是你可以创建标准的方法。

让我们一起来看看数组混排的例子,我可以创建一个接受数组的混排方法:

function shuffle(arr) {
    for (let i = arr.length - 1; i > 0; i--) {
        const random = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[random]] = [arr[random], arr[i]];
    }
    return arr;
}

const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(shuffle(input)); // [ 7, 8, 10, 3, 2, 9, 5, 1, 4, 6 ]

注意:你可能会得到一个和我不同的输出结果因为我们是随机混排数组的。

我们可以将混排方法添加到原型上,然后就可以像使用内置方法一样了(pop、slice、sort)。

Array.prototype.shuffle = function () {
    let arr = this;
    for (let i = arr.length - 1; i > 0; i--) {
        const random = Math.floor(Math.random() * (i + 1));
        [arr[i], arr[random]] = [arr[random], arr[i]];
    }
    return arr;
}

const input = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
console.log(input.shuffle()); // [ 2, 4, 9, 8, 5, 7, 3, 10, 6, 1 ]

现在我们已经在原型上添加了该方法,接着就可以使用任何数组以 input.shuffle() 的形式调用。

缺点

多数开发者不建议直接扩展内置类或对象,这是一个有争议的话题。下面列出来一些缺点:

  1. ECMAScript 可能会在后面的版本提供类似的方法,比如:下一个版本的 ES 提供 shuffle ,那将与我们的方法冲突。
  2. 我们可以任意的修改存在方法的功能,例如:我可能会通过自定义功能来改变 slice 方法。对于整个应用不是一个好的实践,因为其它地方可能会依赖该内置方法,导致我会破坏整个组织内很多同事的代码功能。