【问题标题】:Is it possible to create custom operators in JavaScript?是否可以在 JavaScript 中创建自定义运算符?
【发布时间】:2013-12-22 10:36:08
【问题描述】:

在数学课中,我们学习了如何定义新的运算符。例如:

(ℝ, ∘), x ∘ y = x + 2y

这定义了 法律。对于任何实数 xyx ∘ yx + 2y

例如:2 ∘ 2 = 2 + 4 = 6.


可以在 JavaScript 中定义这样的运算符吗?我知道一个函数可以完成这项工作:

function foo (x, y) { return x + 2 * y; }

但我想要以下语法:

var y = 2 ∘ 2; // returns 6

而不是这个:

var y = foo(2, 2);

哪个是最接近这个问题的解决方案?

【问题讨论】:

  • 这个的另一个名字是中缀函数表示法——答案是否定的,你不能
  • 你可以尝试使用现有的操作符来利用valueOf,但在 JavaScript 中就是这样。
  • 我认为定义一个符号在我的键盘上没有的运算符是一个非常糟糕的主意
  • 没有。你不能在 JavaScript 中做到这一点。但是,您可以在 Haskell 中执行此操作。第一行:infixl 6 ∘。第二行:x ∘ y = x + 2 * y.
  • 从技术上讲,您可以通过编写您自己的词法解析器并在<script> 块中定义您自己的脚本类型名称。这种技术被广泛使用。一些著名的例子包括Google Traceur

标签: javascript operators


【解决方案1】:

简短的回答是否定的。 ECMAScript(标准 JS 所基于)不支持运算符重载。

顺便说一句,在 ECMAScript 7 中,您可以在设计自定义 值类型时重载标准运算符的子集。这是关于该主题的slide deck by language creator and Mozilla CTO Brendan Eich。但是,这将不允许任意运算符,并且重载的含义将仅应用于值类型。

可以使用sweet.js 等第三方工具来添加自定义运算符,但这需要额外的编译步骤。

answered with a solution from outside JavaScript 使用 esprima - 这是 更改 JavaScript 并对其进行扩展,它不是原生的。

【讨论】:

  • 可以添加参考吗?这样的算子实现后如何定义?
  • 我怀疑任何版本的 ECMAScript 都具有定义新符号运算符的能力——这通常是为像 haskell 这样的语言保留的。我怀疑它只会与运算符 overloading 一起出现
  • @Eric Haskell 所做的并不是魔法。在 JS 中为中缀表示法引入反引号没有问题 :) 但是,是的,当前提案讨论了运算符重载。
  • @BenjaminGruenbaum:当然,这不是魔法,但是定义符号运算符对于perl 来说是一个滑坡
  • 我在ECMAScript page on value objects 上没有看到提示用户代码可以声明新的值类型
【解决方案2】:

鉴于 ES6 中添加了一些新的标记模板文字功能,我们可以创建自定义 DSL 来处理嵌入式表达式,例如包含不同代数符号的表达式。

例如。 (运行在stackblitz

function math(strings, x, y) {
  // NOTE: Naive approach as demonstration

  const operator = strings[1].replace(/\s/gi, "");

  if (operator == "∘") {
    return x + 2 * y;
  }
  else if (operator == "^") {
    return Math.pow(x, y);
  }
  else {
    return `Unknown operator '${operator}'`;
  }
}

console.log(math`${2} ∘ ${2}`)

请注意,由于标记的模板文字不一定返回字符串作为结果,它们可以返回更复杂的中间 AST 结构来构建表达式,然后可以进一步细化并解释,同时保持接近手头的特定领域语言.我还没有找到任何现有的库可以为 Javascript 执行此操作,但从我所知道的标记模板文字和在 lit-html 等地方的使用情况来看,它应该是一项有趣且非常平易近人的尝试。

【讨论】:

    【解决方案3】:

    没有。你不能在 JS 中这样做。

    IMO 最接近的方法是实现您自己的 对象,该对象具有可链接的接口,也就是“流利的”语法。这样你就可以像按顺序说话一样操作。

    var eq = new YourEquationObject();
    
    // Then operate like 1 - 2 * 3
    eq.add(1).sub(2).mul(3);
    

    不过,细节由您决定。只是给出一个想法。

    【讨论】:

      【解决方案4】:

      没有。 JavaScript 不支持运算符重载。但是您可以为此创建一个类方法

      var mathClass = function(value){
         this.value = value;
      }
      
      mathClass.prototype.toLaw = function(){
         return 2 * this.value;
      }
      
      var y = new mathClass(2)
      2 + y.toLaw(); //2 + 2 * y
      

      【讨论】:

      • 你可以更进一步,将这些添加到Number.prototype,就像我的回答一样
      【解决方案5】:

      您可以通过Number.prototype 上的方法添加伪运算符:

      Object.defineProperty(Number.prototype, 'myOp', {
          value: function(that) {
              return this + 2 * that;
          }
      });
      

      那么所有这些语法都会起作用

      alert( (2).myOp(2) )
      alert( 2 .myOp(2) )
      alert( 2..myOp(2) )
      alert( 2.0.myOp(2) )
      

      2.myOp(2) 不起作用,因为句点被视为小数点

      【讨论】:

        【解决方案6】:

        一组编译成 JS 语言支持自定义操作符。

        我会强调 ReasonML (ocaml-syntax-readable-by-js-folks) 和 Bucklescript (ocaml-to-js-compiler),它们让自定义运算符看起来很整洁:

        例如,连接字符串的运算符可能如下所示:

        let (>|<) = (list, seperator) => Belt.List.reduce(list, "", (a, b) => a ++ seperator ++ b);
        

        然后可以像这样使用:

        [Styles.button, Media.Classes.atLeastTablet] >|< " "
        

        所有这一切的缺点是它必须用这种编译为 js 的语言编写,并且它有很多优点和缺点,但通常这些语言具有你不知道的大量语法糖的吸引力'不进入 js/ts

        【讨论】:

          【解决方案7】:

          阅读答案下方的 cmets。

          显然你不能。这是接近的东西:

          function exec(input) {
              return Function(
                  'return ' + input.replace(/∘( *[\d.]+)/g, '+ 2 * $1') + ';'
              )();
          }
          
          exec('2 ∘ 2'); // 6
          

          【讨论】:

          • (1 + 1) ∘ (1 + 1) 会毁了你的一天
          • @Eric 不错的方法,但 '2 ∘ 2' 是一个字符串。我不想成为一个字符串。
          • @イオニカビザウ:想法是您将脚本标记标记为language="myjavascript",然后有一个小脚本在运行时将您的代码转换为原始javascript
          • 要正确执行此操作,您需要一个 javascript AST 库,例如 acornesprima。如果你想添加新的符号运算符,你可能需要稍微调整一下解析器
          【解决方案8】:

          比短的略长一点,是的,你可以,但它比你在数学课上做的更复杂

          要使用新结构扩展语言,您可以使用 http://esprima.org/ 之类的转换器或任何其他转换器。你需要定义你的语法,编写解析器来解析你的语句,最后添加实际的代码来做数学部分。当这些部分到位后,您就创建了一种新语言,它与 javascript 一样工作,但增加了 运算符的支持。

          添加新语法真的不难,这里是 Facebook 的例子,他们如何添加 => 箭头函数语法

          https://github.com/facebook/jstransform/blob/master/visitors/es6-arrow-function-visitors.js

          【讨论】:

            【解决方案9】:

            我也在问这个问题,这是我的答案:

            function myCustomOperation(string){
            var res = String.fromCharCode(9762);
            var thing = string.replace(/☢/g," + 10 + ");
            thing=thing.replace(/☣/g," * 2 + ");
            thing=thing.replace(/☠/g," / 3 * ");
            return [eval(thing),string+" = "+eval(thing)];
            };
            var thing = myCustomOperation("
            
            3 ☠ 4
            
            ");
            document.write(thing[1]);
            

            【讨论】:

              猜你喜欢
              • 2012-05-04
              • 2014-08-21
              • 2017-07-04
              • 1970-01-01
              • 2023-03-23
              • 2011-09-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多