如何在 switch 语句中使用 instanceof

Posted

技术标签:

【中文标题】如何在 switch 语句中使用 instanceof【英文标题】:How to use instanceof in a switch statement 【发布时间】:2016-07-19 20:43:19 【问题描述】:

我使用自定义错误 (es6-error) 允许我根据他们的类处理错误,如下所示:

import  DatabaseEntryNotFoundError, NotAllowedError  from 'customError';

function fooRoute(req, res) 
  doSomethingAsync()
    .then(() => 
      // on resolve / success
      return res.send(200);
    )
    .catch((error) => 
      // on reject / failure
      if (error instanceof DatabaseEntryNotFoundError) 
        return res.send(404);
       else if (error instanceof NotAllowedError) 
        return res.send(400);
      
      log('Failed to do something async with an unspecified error: ', error);
      return res.send(500);
    ;

现在我宁愿为这种类型的流程使用开关,结果如下:

import  DatabaseEntryNotFoundError, NotAllowedError  from 'customError';

function fooRoute(req, res) 
  doSomethingAsync()
    .then(() => 
      // on resolve / success
      return res.send(200);
    )
    .catch((error) => 
      // on reject / failure
      switch (error instanceof) 
        case NotAllowedError:
          return res.send(400);
        case DatabaseEntryNotFoundError:
          return res.send(404);
        default:
          log('Failed to do something async with an unspecified error: ', error);
          return res.send(500);
      
    );

instanceof 但是不能这样工作。所以后者失败了。

有没有办法在 switch 语句中检查实例的类?

【问题讨论】:

【参考方案1】:

一个不错的选择是使用对象的constructorproperty:

// on reject / failure
switch (error.constructor) 
    case NotAllowedError:
        return res.send(400);
    case DatabaseEntryNotFoundError:
        return res.send(404);
    default:
        log('Failed to do something async with an unspecified error: ', error);
        return res.send(500);

注意constructor 必须与创建对象的那个完全匹配(假设errorNotAllowedError 的一个实例,NotAllowedErrorError 的子类):

error.constructor === NotAllowedErrortrue error.constructor === Errorfalse

这与instanceof 不同,后者也可以匹配超类:

error instanceof NotAllowedErrortrue error instanceof Errortrue

检查this interesting post 的constructor 属性。

【讨论】:

我比我自己的答案更喜欢这个。这样我就不必检查字符串,但可以检查实际对象。但是,我不确定从技术角度来看哪个更明智。 构造函数比它的名字更容易写:自动完成:)。 警告一句:如果你使用 Babel 进行编译,你可能会发现上面的 switch 语句总是遇到默认情况。 Babel 不允许您在不使用 babel-plugin-transform-builtin-extend 的情况下对内置类型(如错误)进行子类化 @EdwardWoolhouse 现在还适用吗?很高兴我看到你在警告【参考方案2】:

解决方法,以避免 if-else。找到here

switch (true) 
    case error instanceof NotAllowedError: 
        return res.send(400);

    case error instanceof DatabaseEntryNotFoundError: 
        return res.send(404);

    default:
        log('Failed to do something async with an unspecified error: ', error);
        return res.send(500);

【讨论】:

这应该是答案,因为它对 JS 的所有风格/风格都“向后兼容”。使用 error.constructor 并不适用于所有浏览器和 Babel 版本 天才的想法!交换条件和案例。 Typescript 目前无法将其识别为类型保护:github.com/microsoft/TypeScript/issues/37178 这比 if else 有什么好处?我认为整点没有重复error? @DavidMulder by if-else 您应该添加更多字符并使用花括号阅读更多代码。如果您需要一些代码用于多种情况(在开箱即用的 switch-case 功能中),一切都会变得更糟。使用 if-else 您应该添加“||”那么条件。所以阅读和写作都很舒服?【参考方案3】:

这种切换情况的替代方法是在错误的构造函数中只包含一个状态字段。

例如,像这样构建你的错误:

class NotAllowedError extends Error 
    constructor(message, status) 
        super(message);
        this.message = message;
        this.status = 403; // Forbidden error code
    

像这样处理你的错误:

.catch((error) => 
  res.send(error.status);
);

【讨论】:

您假设调用者是一个处理 HTTP 通信的函数。将调用者的逻辑与被调用的函数耦合通常不是一个好主意。假设调用者有一个特殊情况,尽管出现 NotAllowed 错误,但响应为 200,现在抛出错误的函数需要了解差异并抛出正确的 NotAllowedError @AlexTes 我很难理解假设调用者是一个处理 HTTP 通信的函数有什么问题。 res.send 还可以考虑原始问题吗?此外,您提到了一个 200 错误的特殊情况。他们可以在 catch 中添加一个 if 来处理这个问题。我的目的是为原始问题提供替代解决方案。如果我误读了这个,我很抱歉,但您似乎将我的答案应用于完全不同的范围? 我唯一的一点是,doSomethingAsync 对它的调用一无所知会更好。由于它会引发错误,并且fooRoute 的工作方式取决于错误中的内容,因此doSomethingAsync 现在可能必须了解fooRoute 的工作方式才能使用正确的状态码引发错误。他们会被绑在一起。 啊!感谢您解释亚历克斯,这是一个非常好的观点。我没有意识到你想把它分开,我想这只是更好的做法。

以上是关于如何在 switch 语句中使用 instanceof的主要内容,如果未能解决你的问题,请参考以下文章

如何在 switch 语句中使用 instanceof

如何在 switch 语句中使用 laravel 模型运行多个 Where 子句

如何在准备中的 switch 语句中使用可选绑定(segue :)

当元素具有多个类时如何在 switch 语句中检查 className

如何在C中使用宏内的switch语句?

如何在 Django 模板中获得“switch-case”语句功能?