【问题标题】:JavaScript - Get an array object from a string variableJavaScript - 从字符串变量中获取数组对象
【发布时间】:2021-03-03 17:13:08
【问题描述】:
var list = "OVER_30 = true || NUM_OF_JACKETS >=3 || COUNT_TOTAL == 500";
var array = getList(); // array[0].OVER_30 = true, array[0].NUM_OF_JACKETS = 5, array[0].COUNT_TOTAL = 500;

if (array[0].OVER_30 = true || array[0].NUM_OF_JACKETS >=3 || array[0].COUNT_TOTAL == 500) { <--- What I want to accomplish
   return true;
}

我有一个名为 list 的字符串变量,其中包含条件。 如何在每个条件前添加 array[0]. 以组合数组和字符串?

var 格式 = 数组 [0]。 + 条件??

【问题讨论】:

  • 你大概可以使用eval()或者解析字符串
  • 你熟悉Function对象的构造函数吗?它们显示在已接受答案的第三个示例中,此处:stackoverflow.com/questions/7650071/… - 使用这样的构造函数,可以解析您提供的字符串(在更正语法错误之后),然后生成代表函数的字符串将产生所需结果的主体。

标签: javascript arrays string object


【解决方案1】:

你仍然需要eval,但你可以解构对象并执行eval

这种方法需要使用比较运算符进行有效检查

OVER_30 == true

而不是使用= 的赋值运算符。

const
    array = [
        { OVER_30: true, NUM_OF_JACKETS: 5, COUNT_TOTAL: 500 },
        { OVER_30: false, NUM_OF_JACKETS: 2, COUNT_TOTAL: 400 }
    ],
    list = "OVER_30 == true || NUM_OF_JACKETS >=3 || COUNT_TOTAL == 500",
    result = array.map(({ OVER_30, NUM_OF_JACKETS, COUNT_TOTAL }) => eval(list));

console.log(result);

【讨论】:

  • 非常好。很难掌握但很好:)
【解决方案2】:

我只能为你找到 eval

您需要确保语句格式正确,包含空格和正确的= 数量

所以我在这里使用两个地图和一个some - 如果你有 && 而不是 ||您需要every,它将返回一个组合结果,这意味着 [true,true,true] 为真,任何其他组合为假

使用some 将返回一个组合结果,任何为真为真

const list = "OVER_30 === true || NUM_OF_JACKETS >= 3 || COUNT_TOTAL === 500";

const array = [
{ OVER_30 : true, NUM_OF_JACKETS : 5, COUNT_TOTAL : 500},
{ OVER_30: false, NUM_OF_JACKETS: 2, COUNT_TOTAL: 400 },
{ OVER_30: true, NUM_OF_JACKETS: 2, COUNT_TOTAL: 400 }
]

const tests = list.split("||");

const results = array.map(item => tests.map(test => {
    const [name, oper, val] = test.trim().split(" ");
    const statement = `${item[name]} ${oper} ${val}`
    return eval(statement)
  }).some(test => test)
)
console.log(results)

【讨论】:

    【解决方案3】:

    将您的运算符从=(赋值)更改为=====(比较)作为第一个条件。或者只使用OVER_30。因此:

    "OVER_30 || NUM_OF_JACKETS >=3 || COUNT_TOTAL === 500"
    

    您可以使用new Function()()构造函数和Array#some()方法如下:

    list.split('||').some(cond => new Function(`return array[0].${cond}`)())
    

    如果至少有一个条件为真,则返回true

    var list = "OVER_30 || NUM_OF_JACKETS >=3 || COUNT_TOTAL === 500";
    var array = [
       {OVER_30:true, NUM_OF_JACKETS:5, COUNT_TOTAL:500}, 
       {OVER_30:true, NUM_OF_JACKETS:0, COUNT_TOTAL:100},
       {OVER_30:false, NUM_OF_JACKETS:2, COUNT_TOTAL:200},
       {OVER_30:false, NUM_OF_JACKETS:1, COUNT_TOTAL:400}
    ];
    
    for(let i in array) { 
        if( list.split('||').some(cond => new Function(`return array[${i}].${cond}`)()) ) {
            console.log( 'returning true.' );
        } else {
            console.log( '....false!' );
        }
    };
    
    list.split(' || ').forEach(cond => console.log( new Function(`return array[1].${cond}`)() ));

    【讨论】:

      【解决方案4】:

      不使用eval 而是使用简单的解析器然后进行评估的方法:

      //helper functions
      const peek = arr => arr[arr.length - 1];
      const isOperator = token => typeof token === "object";
      
      //available operators
      const operators = new Map([
        [ "===", { precedence: 2, operation: (a, b) => a === b }],
        [ ">=",  { precedence: 2, operation: (a, b) => a >= b  }],
        [ "||",  { precedence: 1, operation: (a, b) => a || b  }],
      ]);
      
      //convert into operators and operands
      const tokenize = str => str.split(/\s+|\b/)
        .map(token => operators.has(token) ? operators.get(token) : token );
      
      //convert literal tokens and binary operators into reverse polish notation
      const parse = tokens => {
        const opStack = [];
        const output = [];
        
        for (const token of tokens) {
          if (isOperator(token)) {
            while(isOperator(peek(opStack)) && token.precedence <= peek(opStack).precedence) {
              output.push(opStack.pop());
            }
              
            opStack.push(token);
          } else {
            output.push(token);
          }
        }
        
        return output.concat(opStack.reverse());
      };
      
      const consume = (rpnTokens, obj) => {
        const output = [];
        for(const token of rpnTokens) {
          if (isOperator(token)) {
            const b = output.pop();
            const a = output.pop();
            
            const result = token.operation(a, b);
            
            output.push(result);
          } else {
            const value = token in obj 
              ? obj[token] //object properties - fetch from object
              : JSON.parse(token); //others convert into values
              
            output.push(value);
          }
        }
        
        return output[0];
      }
      
      // ▲▲▲ code ▲▲▲
      
      // ▼▼▼ usage ▼▼▼
      
      const list = "OVER_30 === true || NUM_OF_JACKETS >= 3 || COUNT_TOTAL === 500";
      
      const array = [
        { OVER_30: true,  NUM_OF_JACKETS: 7, COUNT_TOTAL: 500 }, //true
        { OVER_30: false, NUM_OF_JACKETS: 7, COUNT_TOTAL: 500 }, //true
        { OVER_30: false, NUM_OF_JACKETS: 1, COUNT_TOTAL: 500 }, //true
        { OVER_30: false, NUM_OF_JACKETS: 1, COUNT_TOTAL: 100 }, //false
        { OVER_30: true,  NUM_OF_JACKETS: 1, COUNT_TOTAL: 100 }  //true
      ];
      
      const tokens = tokenize(list);
      const rpn = parse(tokens);
      
      for (const item of array) {
        console.log(consume(rpn, item));
      }
      1. 字符串被转换成记号 "OVER_30 === true || NUM_OF_JACKETS &gt;= 3 || COUNT_TOTAL === 500" 将表示为
      [ "OVER_30", OP[===], "true", OP[||], "NUM_OF_JACKETS", OP[>=], "3", OP[||], "COUNT_TOTAL", OP[===], "500" ]
      
      1. 随后the shunting-yard 算法的简化版本将令牌重新排序为reverse Polish notation 生成:
      [ "OVER_30", "true", OP[===], "NUM_OF_JACKETS", "3", OP[>=], OP[||], "COUNT_TOTAL", "500", OP[===], OP[||] ]
      
      1. 列表被一一浏览。

        3.1。任何操作数都被转换为一个值并添加到堆栈中:

        • 作为属性存在于对象上的东西通过从对象中获取值进行转换
        • 其他任何内容都假定为 JavaString 原语并转换为值

        3.2。运算符应用于最后两个值,并将结果放入堆栈。

      最后,堆栈上只有一个结果,这是所有令牌求值的结果。

      这假设给出了一个格式良好且逻辑良好的字符串。

      该解决方案现在可以处理任何有效的表达式,并且可以使用文字。只需将它们添加到配置中即可使用更多运算符进行扩展:

      //helper functions
      const peek = arr => arr[arr.length - 1];
      const isOperator = token => typeof token === "object";
      
      //available operators
      const operators = new Map([
        [ "+",   { precedence: 3, operation: (a, b) => a + b   }], //support addition
        [ "===", { precedence: 2, operation: (a, b) => a === b }],
        [ ">=",  { precedence: 2, operation: (a, b) => a >= b  }],
        [ "||",  { precedence: 1, operation: (a, b) => a || b  }],
      ]);
      
      //convert into operators and operands
      const tokenize = str => str.split(/\s+|\b/)
        .map(token => operators.has(token) ? operators.get(token) : token );
      
      //Shunting-yard algorithm for literal tokens and binary operators into reverse polish notation
      const parse = tokens => {
        const opStack = [];
        const output = [];
        
        for (const token of tokens) {
          if (isOperator(token)) {
            while(isOperator(peek(opStack)) && token.precedence <= peek(opStack).precedence) {
              output.push(opStack.pop());
            }
              
            opStack.push(token);
          } else {
            output.push(token);
          }
        }
        
        return output.concat(opStack.reverse());
      };
      
      const consume = (rpnTokens, obj) => {
        const output = [];
        for(const token of rpnTokens) {
          if (isOperator(token)) {
            const b = output.pop();
            const a = output.pop();
            
            const result = token.operation(a, b);
            
            output.push(result);
          } else {
            const value = token in obj 
              ? obj[token] //object properties - fetch from object
              : JSON.parse(token); //others convert into values
              
            output.push(value);
          }
        }
        
        return output[0];
      }
      
      
      
      console.log(consume(parse(tokenize("5 >= 6")), {}));         //false
      console.log(consume(parse(tokenize("7 >= 6")), {}));         //true
      console.log(consume(parse(tokenize("4+1>=6")), {}));         //false
      console.log(consume(parse(tokenize("4+3>=6")), {}));         //true 
      console.log(consume(parse(tokenize("1+1+1 === 3")), {}));    //true
      console.log(consume(parse(tokenize("true || false")), {}));  //true
      console.log(consume(parse(tokenize("false || false")), {})); //true
      console.log(consume(parse(tokenize("apples === oranges+2")),   //true
        { apples: 42, oranges: 40})
      ); 

      【讨论】:

        猜你喜欢
        • 2022-10-21
        • 1970-01-01
        • 2023-04-10
        • 2012-01-29
        • 2020-11-06
        • 2021-12-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多