如何从string构建Array.filter的谓词

时间:2017-11-29 05:59:30

标签: javascript

我有一个数组,我想从字符串

构建过滤谓词
var testArray=[{Id:1,IsChecked:true},{Id:2,IsChecked:false},{Id:3,IsChecked:false}];
var predicate='IsChecked==true && Id<3'

var filteredArray= testArray.filter(i=>i ????predicate) ????

我试过了

//this works
var predicate='IsChecked==true'
var filterFunction=new Function("i","return i." + predicate)

//this throw an error (Id is not defined)
var predicate='IsChecked==true && Id<3'
var filterFunction=new Function("i","return i." + predicate)

如何从字符串构建谓词?

欢迎任何使用其他javascript库(如ramda和loadash)的想法。

2 个答案:

答案 0 :(得分:1)

要从字符串制作,您需要使用eval,这是不好的做法。

相反,predicte可以是一个函数,它接受一个项目并使用它来执行条件。您只需要将此功能传递到filter

&#13;
&#13;
const testArray = [ 
   { Id:1, IsChecked: true},
   { Id:2, IsChecked: false}
];

const predicate = (item) => item.IsChecked == true;

const filteredArray = testArray.filter(predicate);

console.log(filteredArray);
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您可以先将谓词处理为函数。

function processPredicate( predicate )
{
   var items = predicate.split(/[\W$]+/); //split by a non word character including $ which can also be part of an identifier

   //if the operand if all numbers, then parse them into a number
   var operand1 = parseToNative( items[0] );
   var operand2 = parseToNative( items[1] );

   var operator = predicate.match(/[\W$]+/)[0];
   var fReturn = () => false;
   switch (operator)
   {
      case "<":
         fReturn = (obj) => obj[operand1] < operand2;
         break;
      case ">":
         fReturn = (obj) => obj[operand1] > operand2;
         break;
      case "<=":
         fReturn = (obj) => obj[operand1] <= operand2;
         break;
      case ">=":
         fReturn = (obj) => obj[operand1] >= operand2;
         break;
      case "==":
         fReturn = (obj) => obj[operand1] == operand2;
         break;
      case "===":
      default:
         fReturn = (obj) => obj[operand1] === operand2;
   }
   return fReturn;
}

<强>演示

function parseToNative( val )
{
   return  isNaN( val ) ? (val == "true" || val == "false" ? val === "true" : val ) : Number(val);
}

function processPredicate( predicate )
{
   var items = predicate.split(/[\W$]+/); //split by a non word character including $ which can also be part of an identifier
   
   //if the operand if all numbers, then parse them into a number
   var operand1 = parseToNative( items[0] );
   var operand2 = parseToNative( items[1] );
   
   var operator = predicate.match(/[\W$]+/)[0];
   var fReturn = () => false;
   switch (operator)
   {
      case "<":
         fReturn = (obj) => obj[operand1] < operand2;
         break;
      case ">":
         fReturn = (obj) => obj[operand1] > operand2;
         break;
      case "<=":
         fReturn = (obj) => obj[operand1] <= operand2;
         break;
      case ">=":
         fReturn = (obj) => obj[operand1] >= operand2;
         break;
      case "==":
         fReturn = (obj) => obj[operand1] == operand2;
         break;
      case "===":
      default:
         fReturn = (obj) => obj[operand1] === operand2;
   }
   //console.log( operand1, operand2, operator, fReturn );
   return fReturn;
}

var testArray=[{Id:1,IsChecked:true},{Id:2,IsChecked:false}];
var predicate1=processPredicate('IsChecked==true')
var predicate2=processPredicate('Id<2')

var output = testArray.filter( function(item){
  return Object.keys( item ).some( s => predicate1( item ) );
})
console.log( output );

output = testArray.filter( function(item){
  return Object.keys( item ).some( s => predicate2( item ) );
})
console.log( output );