javascript - 区间验证

标签 javascript validation

我们有三个不同的网页,其中包含用于添加主实体详细信息的网格。

Detail对象可以通过javascript表达

var detail = {
     Description: 'Detail',
     MinPercentage: 0,
     MaxPercentage: 20
}

现在,我们要在发送到服务器之前验证这些详细信息。

验证

  • 不得有任何交集。即 detail('Detail1', 0, 20) 和 detail('Detail2', 15, 30) 无效,因为 15 到 20 是常见的。
  • 细节保存从给定的最小值到给定的最大值的值。即,detail('Detail1', 0, 20) 和 detail('Detail2', 20, 40) 保存从 0 到 40 的值。如果给定最小值为 0,给定最大值为 40,则它们有效。

对功能的期望

  • 因为我想编写一个在多个地方使用的函数,所以应该尽可能通用。

然后,我编写了一个名为 areIntervalsValid 的函数,但我不确定如何处理输入错误的调用、抛出异常、返回最佳结构化结果,而且我想知道执行的最佳方式是什么验证。


// Returns array of detail object to test.
var getDetails = function () {
    var detail1 = { Description: 'Detail1', MinPercentage: 0, MaxPercentage: 20 }
    var detail2 = { Description: 'Detail2', MinPercentage: 40, MaxPercentage: 60 }
    var detail3 = { Description: 'Detail3', MinPercentage: 60, MaxPercentage: 72 }
    var detail4 = { Description: 'Detail4', MinPercentage: 72, MaxPercentage: 100 }
    var detail5 = { Description: 'Detail5', MinPercentage: 20, MaxPercentage: 40 }

    return new Array(detail1, detail2, detail3, detail4, detail5);
}

// Performs type checking, logical validation, and requirements validation.
var areIntervalsValid = function (items, min, max, minProperty, maxProperty) {
    // Returned object.
    var result = {
        Success: false,
        Message: ''
    }

    // Checks arguments have expected types.
    var validateFunctionCall = function () {
        if (!Array.isArray(items) || typeof min !== 'number' || typeof max !== 'number' || typeof minProperty !== 'string' || typeof maxProperty !== 'string')
            throw 'An error occurred while processing validation.';
        if (!items.length || min > max)
            throw 'An error occurred while processing validation.';
    }

    // Checks [minProperty] of detail that has minimum [minProperty] == min
    // and [maxProperty] of detail that has maximum [minProperty]
    var validateIntervalBasics = function () {
        if (items[0][minProperty] != min || items[items.length - 1][maxProperty] != max)
            throw 'Start and end values of interval do not match minimum - maximum values.';
    }

    // Checks @item has [minProperty] and [maxProperty].
    var validateHasProperty = function (item) {
        if (!item.hasOwnProperty(minProperty) || !item.hasOwnProperty(maxProperty)) {
            throw 'An error occurred while processing validation.';
        }
    }

    try {
        validateFunctionCall();

        // Sorts array of details in according to [minProperty].
        items.sort(function (item1, item2) { return item1[minProperty] > item2[minProperty] });

        validateIntervalBasics();

        var totalDiff = 0, currentItem;

        // Algorithm part. 
        for (var i = 0; i < items.length; i++) {
            currentItem = items[i];
            validateHasProperty(currentItem);
            totalDiff += currentItem[maxProperty] - currentItem[minProperty];
            if (i != items.length - 1 && currentItem[maxProperty] > items[i + 1][minProperty]) { // Finds intersections.
                throw "There are intersected values: " + currentItem[maxProperty] + " - " + items[i + 1][minProperty];
            }
        }

        // Checks second validation.
        if (totalDiff != max - min) {
            throw 'Total interval sum is not equal to ' + (max - min);
        }

        result.Success = true;

        return result;

    } catch (e) {
        console.log(e);
        result.Message = e;

        return result;
    }
}

然后,我这样调用函数:

areIntervalsValid(getDetails(), 0, 100, "MinPercentage", "MaxPercentage");

如何使函数更可靠、通用和快速?

最佳答案

如果您使用函数式编程原则(尤其是递归),这可以以更好的方式完成。

这个问题有我的解决方案。没有数据类型验证逻辑,因为我相信你可以自己做:

// Numbers and intervals comparison logic
function intervalsIntersect(start1, end1, start2, end2) {
  return inBetween(start1, start2, end2) || inBetween(end1, start2, end2);
}

function inBetween(value, start, end){
  return Math.max.apply(null, arguments) != value && Math.min.apply(null, arguments) != value;
}

// Validation logic
function getDetailsIntersectionReport(interval1, interval2) {
  var comparisonResult = intervalsIntersect(interval1.MinPercentage, interval1.MaxPercentage, interval2.MinPercentage, interval2.MaxPercentage);
  return comparisonResult ? ('[' + interval1.Description + ' instersects with ' + interval2.Description + '], ') : '';
}

function compareHeadWithTailFunctionFactory(head, comparatorFunction) {
  return function ( previous, item) {
    return previous + comparatorFunction(head, item);
  }
}

// you have to inject custom comparator function to make this function generic
function validateWithReport(list, comparatorFunction) {
  if (list.length <= 1) { // return if there is nothing to compare
    return '';
  }
  var head = list[0];
  var tail = list.slice(1);
  return tail.reduce(compareHeadWithTailFunctionFactory(head, comparatorFunction), 
  '' // initial value - empty string
  ) + validateWithReport(tail, comparatorFunction);

}

function validateIntervals(intervals) {
  var result = validateWithReport(intervals, getDetailsIntersectionReport);
  if (result.length) {
    throw new Error('There are intersecting intervals: ' + result);
  }
  return true;
}

// Unit test with Jasmine
describe('validation with report', function() {
  
  var intervalsWithoutIntersections = [
    { Description: 'Detail1', MinPercentage: 0, MaxPercentage: 20 },
    { Description: 'Detail2', MinPercentage: 40, MaxPercentage: 60 },
    { Description: 'Detail3', MinPercentage: 60, MaxPercentage: 72 }
  ];

  var intervalsWithIntersections = [
    { Description: 'Detail4', MinPercentage: 0, MaxPercentage: 21 },
    { Description: 'Detail5', MinPercentage: 20, MaxPercentage: 60 },
    { Description: 'Detail6', MinPercentage: 60, MaxPercentage: 72 }
  ];  
  
  it('should report with exception about error', function() {
    expect( function() { // wrapping into closure to catch error properly
      validateIntervals(intervalsWithIntersections)
    }).toThrowError();
  });

  it('should report validation with true', function() {
    expect(validateIntervals(intervalsWithoutIntersections)).toBeTruthy();
  });

});

关于javascript - 区间验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31160344/

相关文章:

javascript - 确认删除在 Chrome 中有效,在 Firefox 中无效

javascript - 提示与 Window.prompt

javascript - TinyMce 在按下 Return 时从当前 block 元素复制类

php - Laravel:在自定义登录中集成 Throttle

Symfony 3 约束验证日期或日期时间

Hibernate validator 在运行时更改区域设置

javascript - 循环遍历所有符合条件的元素

asp.net-mvc-3 - MVC3 中 [DataType(DataType.Email)] 的验证失败

validation - 在 Yii 中执行 "massive assignment"时是否执行验证?

javascript - 在 await 之后调用 setState 时状态立即可用