簡體   English   中英

從數組構建布爾表達式並在javascript中一次評估整個表達式

[英]Build boolean expression from arrays and evaluate entire expression at one time in javascript

我有兩個數組 - 一個包含布爾值,另一個包含運算符:

to_eval = [true, true, false, false]
ops=['&&', '||', '&&']

出於這個我想建立一個表達

result = true && true || false && false

哪個應該根據優先規則評估為真

如果我遍歷評估的數組,結果是錯誤的。

我可以構建一個字符串並使用 Eval 或 Function - 但從我一直在閱讀的內容來看,這可能會導致 Web 應用程序中的安全問題。

Javascript中是否有一種方法可以構建表達式而不對其進行評估,直到它完全形成,以便在不使用Eval或Function的情況下觀察優先規則?

您可以使用Array#reduce安全地為受信任的邏輯運算符創建映射函數:

但是這種從左到右評估的方式沒有優先級,所以true && true || false && false true && true || false && false將評估false 如果您想要更准確的結果,例如 JavaScript 如何解析事物,使用eval並進行適當的清理會更容易。

 const to_eval = [true, true, false, false]; const ops = ['&&', '||', '&&']; const ops_map = { '&&': (a, b) => a && b, '||': (a, b) => a || b }; const result = to_eval.reduce((acc, cur, i) => ops_map[ops[i-1]](acc, cur)); console.log(result);

通過適當的清理,您可以安全地使用eval

 const evaluate = (to_eval, ops = []) => { const expression = to_eval.reduce((acc, cur, i) => { let left = i === 1 ? !!acc : acc; let op = {'&&': '&&', '||': '||'}[ops[i-1]]; if(typeof op !== 'string') { op = '||'; // fallback } let right = !!cur; return `${left} ${op} ${right}` }); const result = eval(expression); console.log(expression, ' => ', result); return result; } const to_eval = [true, true, false, false] const ops = ['&&', '||', '&&']; evaluate(to_eval, ops); evaluate([true], []); evaluate(['alert(1)', 0, false], ['alert(2)', 'hasOwnProperty']);

如果確定您的兩個數組具有預期值(布爾值和預期運算符),您可以安全地調用eval 所以只需添加一些代碼來驗證兩個給定的輸入。

您可以執行以下操作:

 function evaluate(bools, ops) { // Verify the given arguments are as expected if (!ops.every(op => ["&&", "||"].includes(op))) throw "invalid operator"; if (!bools.every(bool => typeof bool === "boolean")) throw "invalid operand"; if (bools.length !== ops.length + 1) throw "length mismatch"; return eval(bools.map((bool, i) => bool + " " + (ops[i] ?? "")).join(" ")); } let to_eval = [true, true, false, false]; let ops = ['&&', '||', '&&']; let result = evaluate(to_eval, ops); console.log(result);

如果你清理輸入,你可以使用 eval (IE,驗證所有令牌都來自一個非常特定的允許令牌列表)。

 function safeEval(expression) { const allowed = ['true', 'false', '&&', '||']; if (expression.split(/\s+/).every(token => allowed.includes(token))) { return eval(expression); } else { throw Error('Encountered forbidden token.'); } } console.log(safeEval('true && true || false && false')); console.log(safeEval('undefined'));

這遠不是您可以編寫的最有效的代碼,但它很簡單並且可以完成工作,並且添加對其他運算符和括號的支持是微不足道的。

或者,您可以按照您希望的優先順序自行評估運算符:

 const expression = [true, '&&', true, '||', false, '&&', false]; for (let i = 0; i < expression.length; ++i) { if (expression[i] === '&&') { const left = expression[i - 1]; const right = expression[i + 1]; expression.splice(i - 1, 3, left && right); } } console.log(expression); for (let i = 0; i < expression.length; ++i) { if (expression[i] === '||') { const left = expression[i - 1]; const right = expression[i + 1]; expression.splice(i - 1, 3, left || right); } } console.log(expression);

如果要添加對許多運算符的支持,您可能希望使此代碼更健壯且重復性更少,但這至少可以幫助您入門。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM