【问题标题】:How to process two Array Objects without using EVAL如何在不使用 EVAL 的情况下处理两个数组对象
【发布时间】:2020-12-21 07:29:35
【问题描述】:

我想处理两个对象。

obj1 具有公式的数组对象。

obj2 有值。 我想处理/计算这两个对象以获得结果,使得 obj1 中存在的键成为输出中的实际键,并使用公式处理值。用 EVAL 做了,但不想用 eval 它。

请建议任何其他方法来做同样的事情。

const obj1 = [{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'fTime', 
  PTag: '(FaultHrs*360)+(FaultMins*60)+FaultSecs',    __v: 0 },
  { _id: '5 f467650890a7444d8d9ea5b', keyname: 'rTime',
  PTag: '(RunHrs*360)+(RunMins*60)+RunSecs', __v: 0 }
]
const obj2 = { FaultHrs: 2, FaultMins: 0, FaultSecs: 49, RunHrs: 1, RunMins: 0, RunSecs: 0,}

const res = obj1.reduce((res, k) => {
  // find out parameters in formula
  const matches = k.PTag.match(/[a-zA-Z]+/g);

  // substitute them with numbers
  const newTag = matches.reduce((tag, m) => tag.replace(m, obj2[m] || 0), k.PTag);

  // calculate result
  res[k.keyname] = eval(newTag);

  return res;
}, {});

console.log(res)

【问题讨论】:

  • 如果输入是可信的——保证是一个数学表达式,没有不安全的代码——那么eval可能是最好的选择。这并不是绝对的邪恶,只是它通常不是正确的选择 - 但这是一种情况,IMO
  • @CertainPerformance 不应该使用 new Function() 而不是 eval()
  • @Ifaruki 我看不出有什么理由比另一个更喜欢这里,你有什么想法吗?
  • @CertainPerformance 我读到new Function() 更好更快,但他们没有详细解释。如果你看一下速度比较measurethat.net/Benchmarks/Show/2858/0/eval-vs-new-function实际上是有区别的
  • 感谢您的帮助,我会尝试新功能。

标签: javascript node.js arrays json object


【解决方案1】:

您可以尝试使用New Function() 构造,而不是eval()。更改代码行

 res[k.keyname] = eval(newTag);

进入

res[k.keyname] = (new Function(`return ${newTag};`))();

但实际上它是相同的 eval()。或者您可以尝试通过抽象语法树来滚动您自己的数学表达式解析器,但互联网上已经有很多这样的解析器,而且不能保证您的解析器会优于集成和经过时间测试的 JS 引擎表达式解析器。

【讨论】:

  • 谢谢,新功能按预期工作。我想知道 - 如何处理像 6.7452824E7 这样的值,并想知道我是否使用正确的方法来处理对象数组。
  • 用特定字符转义表达式中的变量,将其标记为不同于用于科学表示数字的E 符号,如PTag: '(_RunHrs*360)+(_RunMins*60)+_RunSecs'。然后只匹配那些可替换的字符,比如const matches = k.PTag.match(/_[a-zA-Z]+/g);。这样,您将跳过处理不是变量的内容。
  • 我需要更多帮助,我的参数很少包含下划线和数字。所以当我像这样添加它们时 const matches = k.PTag.match(/[a-zA-Z0-9_]+/g);我的输出出错了。
  • 如何在公式中转义变量只是您的喜好 - 只需使用之前从未存在于变量中的符号转义即可。也许@var@ 或者甚至像::var:: 这样的符号火车。并且不要忘记正确更改与您的变量匹配的正则表达式!
【解决方案2】:

您可以尝试使用 math.js 之类的模块,它包含一个不使用 eval 底层的评估函数(我相信旧版本会这样做)。

还是有安全隐患,在math.js文档math.js security中有详细说明,但是应该比直接使用eval要低。

const obj1 = [{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'fTime', 
  PTag: '(Fault_Hrs1*360)+(Fault_Mins1*60)+Fault_Secs1',    __v: 0 },
  { _id: '5 f467650890a7444d8d9ea5b', keyname: 'rTime',
  PTag: '(RunHrs*360)+(RunMins*60)+RunSecs', __v: 0 }
]
const obj2 = { Fault_Hrs1: 2, Fault_Mins1: 0, Fault_Secs1: 49, RunHrs: 1, RunMins: 0, RunSecs: 0,}
const res = obj1.reduce((res, k) => {
  // find out parameters in formula
  const matches = k.PTag.match(/([a-zA-Z]{1}[a-zA-Z0-9_]+)/g);
  
  // substitute them with numbers
  const newTag = matches.reduce((tag, m) => tag.replace(m, obj2[m] || 0), k.PTag);
  // calculate result, using math.js evaluate function.
  res[k.keyname] = math.evaluate(newTag);

  return res;
}, {});

console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/7.2.0/math.js" integrity="sha512-O3GZu6Lz0va4Lk7IuF3CjKx5Jfxi35Gcx3oAjH7m7KRP5xvqorrInDpg3OFVJ6dMPn03vHiwgkgPT/hWfguVfQ==" crossorigin="anonymous"></script>

【讨论】:

  • 感谢您的回答,数学评估工作正常。只是想知道有没有办法处理像“6.7452824E7”这样包含E的值。
  • 我相信 math.js 应该处理这种格式,我会在我的答案中添加一个示例..
  • 我需要更多帮助,我在 PTag 中的参数很少包含下划线和数字。所以当我像这样添加它们时 const matches = k.PTag.match(/[a-zA-Z0-9_]+/g);我的输出出错了。
  • 嘿@GunjanAnshul,我已经更新了答案。问题是如果我们使用 (/[a-zA-Z0-9_]+/g 作为正则表达式,那么我们将得到数字作为匹配项。所以我添加了 PTag 以字母开头的要求字符。这将给出正确的答案。
  • 非常感谢,您节省了很多时间。
【解决方案3】:

Math.js 评估函数工作正常,但是当像 3.2477216E7 这样的值出现包含字母“E”时,它就会中断。你能告诉我,如何处理。

const obj1 = [{ _id: '5 f467650890a7444d8d9ea5b', keyname: 'fTime', 
  PTag: '(FaultHrs*360)+(FaultMins*60)+FaultSecs',    __v: 0 },
  { _id: '5 f467650890a7444d8d9ea5b', keyname: 'rTime',
  PTag: '(RunHrs*360)+(RunMins*60)+RunSecs', __v: 0 }
]
const obj2 = { FaultHrs: 2, FaultMins: 0, FaultSecs: 3.2477216E7, RunHrs: 1, RunMins: 0, RunSecs: 3.2477063E7}

const res = obj1.reduce((res, k) => {
  // find out parameters in formula
  const matches = k.PTag.match(/[a-zA-Z]+/g);

  // substitute them with numbers
  const newTag = matches.reduce((tag, m) => tag.replace(m, obj2[m] || 0), k.PTag);

  // calculate result, using math.js evaluate function.
  res[k.keyname] = math.evaluate(newTag);

  return res;
}, {});

console.log(res)
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/7.2.0/math.js" integrity="sha512-O3GZu6Lz0va4Lk7IuF3CjKx5Jfxi35Gcx3oAjH7m7KRP5xvqorrInDpg3OFVJ6dMPn03vHiwgkgPT/hWfguVfQ==" crossorigin="anonymous"></script>

【讨论】:

    猜你喜欢
    • 2015-06-21
    • 2018-01-15
    • 2021-07-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-22
    • 1970-01-01
    相关资源
    最近更新 更多