如何有条件地合并JavaScript中列表中的某些元素?

问题描述:

我正在构建这个构建器模式,我想将列表中的某些元素合并在一起。但我想以更清晰的方式来做到这一点。这是我迄今为止提出的那种方法,但我相信有更好的方法来做到这一点。如何有条件地合并JavaScript中列表中的某些元素?

function FiltersBuilder() { 
    this.filters = []; 
}; 

FiltersBuilder.prototype.addFilter = function(options) { 
    var filter = { 
    'type': 'selector', 
    'dimension': options.dimension, 
    'value': options.value 
    } 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.addRegexFilter = function(options) { 
    var filter = { 
    'type': 'regex', 
    'dimension': options.dimension, 
    'pattern': options.value 
    } 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.not = function() { 
    var not = { 
    'type': 'not' 
    }; 
    this.filters.push(not); 
    return this; 
} 

FiltersBuilder.prototype.getFilters = function() { 
    var result = []; 
    this.filters.forEach(function each(filter, index, theFilters) { 
    if (filter.type === 'not') { 
     var filterToMerge = theFilters[index + 1]; 
     var mergedFilter = _.merge(filter, {field: filterToMerge}); 
     result.push(mergedFilter); 
    } else { 
     if(index > 0) { 
     notFilter = theFilters[index - 1]; 
     if(notFilter.type === 'not') { 
      return; 
     } 
     } 
     result.push(filter); 
    } 
    }); 

    return result; 
} 

var filterBuilder = new FiltersBuilder(); 
filterBuilder.addFilter({ 
    dimension: '_o', 
    value: 'origin' 
}); 
filterBuilder.not().addRegexFilter({ 
    dimension: 'cTy', 
    value: 'value' 
}); 

console.log(filterBuilder.getFilters()); 

如果not方法添加过滤器之前被调用,我想合并not过滤器的下一个元素,并且对象添加到列表result。但是,如果在添加过滤器之前未调用not,则不要执行任何操作,只需将过滤器添加到result列表中即可。

https://jsfiddle.net/9wyqbovu/

不是把not作为过滤器被添加到过滤器列表,并处理的时候你得到的过滤器,把它作为改性剂 - 的标志。在FiltersBuilder对象上维护一个not属性,初始化为false,其中FilterBuilders.not的调用将切换。在每个筛选器上,还要添加一个not属性,该属性由标志的当前值设置(然后被重置)FilterBuilders。换句话说:

function FiltersBuilder() { 
    this.filters = []; 
    this.not = false; 
}; 

FiltersBuilder.prototype.addFilter = function(options) { 
    var filter = { 
    'type': 'selector', 
    'dimension': options.dimension, 
    'value': options.value, 
    not: this.not 
    } 
    this.not = false; 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.addRegexFilter = function(options) { 
    var filter = { 
    'type': 'regex', 
    'dimension': options.dimension, 
    'pattern': options.value, 
    not: this.not 
    } 
    this.not = false; 
    this.filters.push(filter); 
    return this; 
} 

FiltersBuilder.prototype.not = function() { 
    this.not = !this.not; 
} 

FiltersBuilder.prototype.getFilters = function() { 
    return this.filters; 
} 

var filterBuilder = new FiltersBuilder(); 
filterBuilder.addFilter({ 
    dimension: '_o', 
    value: 'origin' 
}); 
filterBuilder.not().addRegexFilter({ 
    dimension: 'cTy', 
    value: 'value' 
}); 

console.log(filterBuilder.getFilters()); 

如果您希望能够说filterBuilder.not.addFilter(不not后的括号),然后定义not作为一个getter,即

Object.defineProperty(FiltersBuilder.prototype, "not", { 
    get: function() { 
    this.not = !this.not; 
    return this; 
    } 
}); 
+0

我喜欢你的方法比我好。谢谢! – toy

那么,怎么样,如果我们这样做从右边重复它,并使用unshift代替push

getFilters = function(){ 
    return this.filters.reduceRight(function(results, filter){ 
     if(filter.type === 'not'){ 
      //get filter to 'not' 
      var notFilter = results[0]; 
      Object.assign(notFilter, filter); //Or _.merge 
     } else { 
      results.unshift(filter); 
     } 
     return results; 
    }, []); 
} 

或者,你可以用push代替unshift,抢到的最后一个元素该数组作为否定(而不是第一个)的过滤器并反转结果。

getFilters = function(){ 
    return this.filters.reduceRight(function(results, filter){ 
     if(filter.type === 'not'){ 
      //get filter to 'not' 
      var notFilter = results[results.length - 1]; 
      Object.assign(notFilter, filter); //Or _.merge 
     } else { 
      results.push(filter); 
     } 
     return results; 
    }, []).reverse(); 
}