在JavaScript中何时应该使用类表达式?

3
我最近了解到,JavaScript中也有类表达式(class expressions),就像函数表达式一样。我知道一些关于它的信息(来自MDN):
  1. 类表达式可以省略类名(“绑定标识符”),而使用类语句则不行。

  2. 类表达式允许您重新定义(重新声明)类,而不会抛出SyntaxError。

我理解它的用处,但在哪里应该使用它呢?使用类表达式可以实现什么经典示例,而使用类语句则无法实现,反之亦然?

1
你可以说函数表达式也是一样的,不是吗?但我们仍然使用它们。 - VLAZ
我们经常使用函数表达式,但从未在任何地方看到过类表达式,或者它们可能没有像函数表达式那样受欢迎。 - Apoorva Chikara
它们并不是,但考虑到与函数表达式相比,它们也是非常新的功能。此外,似乎更麻烦去禁止它们并导致不一致,而不是让它们对函数对称。这里有一些很少使用的用例,比如使用动态 mixin 增强现有类。然而,它们的实用性是一个见仁见智的问题。我认为这在理论上是一个很棒的功能,但到目前为止我还没有使用过它。它只是没那么有用。至少对于我写的代码来说是这样。 - VLAZ
2个回答

4

类表达式通常用于子类工厂:

function createClass() {
    return class extends … {
        …
    };
}

这种模式通常用于React高阶组件一种mixin实现方式

使用类表达式的经典示例是什么,无法使用类语句实现,反之亦然?

实际上没有。就像函数声明与表达式一样,它们不提供另一种无法实现的功能,而只是在特定情况下提供更令人愉悦的语法。

3

虽然不多,但只要你在将 class 用作右值时,就会自动使用类表达式(就像使用 function 表达式一样)。

  • One place I've seen class expressions used is when wrapping classes:

    function withLogging(BaseClass) {
         // The object is purely temporary, so we set the
         // name of the class dynamically
         const subclassName = BaseClass.name + "WithLogging";
         const obj = {
             [subclassName]: class extends BaseClass {
                 log(msg) { console.log(msg); }
             },
         };
         return obj[subclassName];
    }
    

    I'm not saying that's a good idea (I'd probably use a mixin, or composition rather than inheritance), but I've seen it done.

       
       function withLogging(BaseClass) {
           // The object is purely temporary, so we set the
           // name of the class dynamically
           const subclassName = BaseClass.name + "WithLogging";
           const obj = {
               [subclassName]: class extends BaseClass {
                   log(msg) { console.log(msg); }
               },
           };
           return obj[subclassName];
       }
       
       const X = withLogging(class Example { });
       console.log(X.name);
       new X().log("Hi there");
       
       

  • Something that looks like a class expression but is in fact more exotic than that is default exporting an unnamed class:

    export default class { /*...*/ }
    

    I really don't like that one, because A)  I don't like default exports, and B)  I don't like unnamed functions/classes (other than really simple callback functions, for instance to map or new Promise).

    It's technically an anonymous class declaration (just as the equivalent would be an anonymous function declaration), but it's very similar to a class expression. (The default export case is the only place the specification allows anonymous class or function declarations.)

  • If you were creating an object with several classes on it:

    const classes = {
         A: class A { /*...*/ },
         B: class B { /*...*/ },
         C: class C { /*...*/ },
    };
    

    (I don't think I've ever done that, but...)


在第一个例子中,没有必要将类分配给一个对象。你可以直接使用return class extends BaseClass { ... } - undefined
1
@user14967413 - 如果你不介意匿名类的话,那是正确的。临时对象的目的,正如注释所说和实际示例所展示的那样,是动态设置类的name属性。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接