在代码中进行额外检查以供内部使用是不错的做法?

时间:2011-04-09 08:48:58

标签: javascript stability

是否可以检查代码中的所有参数和其他条件,如果我知道,我从不传递错误的参数,它应该工作正常(说我已经在该代码之外做了一些检查)。

示例:

此代码:

/**
 * Applies function to all elements of array in specified
 * context.
 * If array is empty, returns null.
 */
MyNameSpace.foreach = function(arr, callback, context) {
   if (!(arr instanceof Array)) {
       throw new Error('first argument is not an array');
   }
   if (typeof callback !== 'function') {
       throw new Error('callback is not a function');
   }
   if (typeof arr.length === 'undefined') {
      throw new Error('Length undefined');
   }

   var con = typeof context === 'object' ? context : window;

   var i = arr.length;
   if ( i <= 0 ) {
       return null;
   }

   for ( j = 0; j < i; j++ ) {
        callback.call(con, j, arr[j]);
   }
}

可能是:

MyNameSpace.foreach = function(arr, callback, context) {
   var con = typeof context === 'object' ? context : window;

   var i = arr.length;
   if ( i <= 0 ) {
       return null;
   }

   for ( j = 0; j < i; j++ ) {
        callback.call(con, j, arr[j]);
   }
}

4 个答案:

答案 0 :(得分:3)

绝对可以是好的做法。它可以帮助您的应用程序的稳定性,并帮助调试。缺点是它可能会使代码混乱(使其难以阅读)并且它会对性能产生影响(尽管对于大多数JavaScript应用程序而言,性能并不重要)。

你必须在每种情况下都有一个观点。这实际上取决于(1)参数不正确的可能性和(2)如果它们会造成多大的伤害。

答案 1 :(得分:1)

软件在测试输入和输出方面的一般原则是:“输入灵活,输出严格”。您应该始终对输入进行额外检查,以便在您的方法获得不期望的内容时,代码不会中断。

答案 2 :(得分:1)

这绝对是一种很好的做法,因为任何使用您的类或函数的代码都可能在不知不觉中传递您可能导致代码崩溃的值。
例如:程序员偶然向我的代码发送了一个NULL指针,该指针必须对指针所指向的对象进行深度复制。
但是因为我在复制构造函数的初始化列表中克隆了指向的实例,所以没有人能够弄清楚程序崩溃的原因。 程序员说我应该检查NULL指针,但最终我们决定继续检查他的结束,因为我们需要保持复制的效率通过初始化列表,这更快。

因此,您可以决定根据以下方式进行检查:
1.使用复制器初始化列表的效率 2.您是否记录了函数/类的输入参数和限制 3.由于恶意输入,您的代码是否会崩溃/出现安全问题 4.您的软件需要什么样的异常处理。

答案 3 :(得分:1)

虽然如果在生产中保持启用它可能会减慢执行速度,但您可以在生产中或在调试期间使用类型检查库:

function TypeEnforce (func, ctx, config) {
    if (!(this instanceof TypeEnforce)) {
        return new TypeEnforce(func, ctx);
    }
    if (typeof func === 'string' && ctx) {
        this.funcString = func;
        func = ctx[func];
    }
    this.ctx = ctx;
    this.autoset = config && config.autoset;
    this.oldFunc = func;
}
TypeEnforce.prototype.argTypes = function (args) {
    var that = this;
    this.reqArgTypesFunc = function () {
        for (var i=0, argl = args.length; i < argl; i++) {
            if (
                (args[i] === 'Array' && Object.prototype.toString.call(arguments[i]) !== '[object Array]') ||
                (args[i] !== 'Array' && typeof arguments[i] !== args[i])
            ) {
                throw 'Argument ' + i + ' [' + arguments[i] + '] should be of type ' + args[i];
            }
        }
        that.oldFunc.apply(that.ctx, arguments);
    };
    if (this.autoset) {
        this.ctx[this.funcString] = this.reqArgTypesFunc;
    }
    return this;
};
TypeEnforce.prototype.props = function (props) {
    var that = this;
    this.reqPropsFunc = function () { 
        for (var p in props) {
            if (typeof arguments[p][props[p]] === 'undefined') {
                throw 'The property "' + props[p] + '" of argument no. ' + p + 
                        ' [' + arguments[p] + '] should not be undefined';
            }
        }
        var method = that.reqArgTypesFunc || that.oldFunc;
        method.apply(that.ctx, arguments);
    };
    if (this.autoset) {
        this.ctx[this.funcString] = this.reqPropsFunc;
    }
    return this;
};
TypeEnforce.prototype.get = function (props) {
    return this.reqPropsFunc || this.reqArgTypesFunc || this.oldFunc;
};

...在您的情况下,您可以按如下方式使用:

if (!MyNameSpace) {
    var MyNameSpace = {};
}
MyNameSpace.foreach = function(arr, callback, context) {
   var con = typeof context === 'object' ? context : window;

   var i = arr.length;
   if ( i <= 0 ) {
       return null;
   }

   for ( j = 0; j < i; j++ ) {
        callback.call(con, j, arr[j]);
   }
};

TypeEnforce('foreach', MyNameSpace, {autoset:true}).
    argTypes(['Array', 'function']).
    props({0:'length'});

MyNameSpace.foreach(['a', 'b'], function (k, v) {
    alert(k+':'+v);
});

使用这种方法,您可以分离丑陋的类型检查代码,如果您在测试期间只需要它,甚至可以禁用它。您可以进一步添加参数或属性值检查方法。