【问题标题】:Using throw in a Javascript expression在 Javascript 表达式中使用 throw
【发布时间】:2012-03-21 15:29:45
【问题描述】:

这是我想做的:

var setting = process.env.SETTING || throw new Error("please set the SETTING environmental variable");
                                     ^^^^^

但是解释器抱怨“语法错误:意外的令牌抛出”。

有没有办法在我们比较值是否为假的同一行中抛出异常?

【问题讨论】:

    标签: javascript node.js throw


    【解决方案1】:

    throw 是一个语句,而不是一个表达式,因此您不能将它用作另一个表达式的一部分。你必须拆分它:

    var setting = process.env.SETTING;
    if (!setting) throw new Error("please set the SETTING environmental variable");
    

    【讨论】:

      【解决方案2】:

      您可以利用 javascript 的功能特性:

      var setting = process.env.SETTING || 
                     function(){ 
                       throw "please set the SETTING environmental variable";
                     }();
      // es201x
      var setting = process.env.SETTING || 
                    (() => {throw `SETTING environmental variable not set`})();
      

      或更通用的创建一个函数来抛出错误并使用它:

      function throwErr(mssg){
          throw new Error(mssg);
      }
      
      var setting = process.env.SETTING || 
                     throwErr("please set the SETTING environmental variable");
      

      我使用的一个 sn-p:

      const throwIf = (
        assertion = false, 
        message = `An error occurred`, 
        ErrorType = Error) => 
            assertion && (() => { throw new ErrorType(message); })();
      
      throwIf(!window.SOMESETTING, `window.SOMESETTING not defined`, TypeError);

      【讨论】:

      • +1 是一个有趣的解决方案,尽管它看起来有点矫枉过正。
      • IIFEs 在 Javascript 中并不少见。我认为这也变得更好看与箭头功能:var setting = process.env.SETTING || (() => {throw "please set $SETTING";})()
      • @Alec 你是对的,我喜欢它看起来超级干净的样子。一般来说,我对这个答案的唯一保留是阅读代码的人不知道发生了什么,它变成了另一种黑盒魔法。初学者甚至可能会认为这就是 throw 在 js 中的工作方式。总有一天他们会自己尝试,然后浪费大量时间来弄清楚他们从哪里学到的以及为什么它不再有效。
      【解决方案3】:

      throw 没有返回值。所以你不能那样使用它。但是,您可以将 throw 包装在一个函数中。那它会起作用的。但是要找到异常的来源会更难。

      【讨论】:

      • Chrome 的调试器支持“异常断点”行为。
      • -1 这是错误的,不回答问题。 JavaScript 中的一切都有返回值,不是吗?如果你不返回任何东西,你只会得到undefined。即使是delete,也可以试试var foo = ""; alert(delete foo);。只是throw 打断了流程,所以你无法真正获取和使用它的返回类型。
      • @ANeves 你不正确。除了函数调用,js 中没有任何东西“返回值”。表达式计算为一个值,但不返回一个值。有什么不同? 'return' 是一个特定的关键字,仅指函数调用结果。语句,如 'throw' 或 'var',绝对不会返回值。说“throw”返回一个值就像说“var”返回一个值。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
      【解决方案4】:

      我看到你在使用 nodejs。

      我认为验证输入参数的最佳方式是断言。 NodeJS 内置了简单的断言模块:http://nodejs.org/api/assert.html

      并使用它,例如,像这样:

      var assert = require('assert');
      
      // ...
      
      function myFunction (param) {
          assert(param, 'please pass param');
          // ...
      }
      

      对于测试环境,你可以这样做:

      require('assert')(process.env.setting, 'please set the SETTING environmental variable');
      

      或者:

      ;(function (a) {
          a(process.env.setting, 'please set the SETTING environmental variable');
          a(process.env.port, 'please set the PORT environmental variable');
      }(require('assert')));
      

      【讨论】:

        【解决方案5】:
        const getenv = require('getenv');
        const setting = getenv('SETTING');
        

        如果 SETTING 不存在,你会得到:

        … getenv.js:14
        throw new Error('GetEnv.Nonexistent: ' + varName + ' does not exist ' +
        ^ Error: GetEnv.Nonexistent: SETTING does not exist and no fallback value provided.
        

        顺便说一句,我的经验告诉我,环境变量的默认值是邪恶的。

        【讨论】:

          【解决方案6】:

          有一个提案草案将 throw 表达式(类似于 C# 7 的 throw expressions)引入 JavaScript/ECMAScript:

          TC39 proposal: Throw Expressions

          【讨论】:

          【解决方案7】:

          用大括号把它包起来

          {throw ...}
          

          或者用函数包裹它(女巫实际上把它包裹在大括号里)

          ()=>{throw ..}
          //or:
          function(){throw..}
          

          【讨论】:

          • 第一个不起作用 (Uncaught SyntaxError: Unexpected identifier),第二个不起作用,除非您 (1) 将其包裹在大括号中以免混淆解析器和 ( 2)添加更多的大括号来实际调用函数:setting = … || (() => {throw …})()
          【解决方案8】:

          不是问题的直接答案,但如果您使用 TypeScript,我发现 runtypes 是手动验证和抛出的一个很好的替代方案。虽然 OP 中的方法在输入类型为 output | null | undefined 或类似的情况下有效,但 runtypes 在输入类型为 any 时也有效,例如在防御性地解码具有已知结构的 JSON 时。

          你会这样使用它:

          import { String } from 'runtypes';
          const setting = String.check(process.env.SETTING)
          

          如果process.env.SETTINGundefined,它会抛出。添加.withConstraint() 以添加其他条件。该库实际上非常强大,不仅可以验证简单类型​​,还可以以类型安全的方式验证记录(接口)、联合等。

          一个缺点是您无法自定义错误消息(“约束检查失败”),这在许多快速而肮脏的情况下是可以的,因为发生错误的行会告诉您问题所在是。

          io-ts 是另一个类似的库,尽管它似乎有一个更复杂的方法并且目前还在不断变化。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2019-10-30
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多