1

我正在编写一个函数来检查参数是否为零,并且它似乎无法正常工作。注意:使用 Chrome 作为我的浏览器,但此代码应支持跨浏览器。

// check all arguments, and make sure they aren't zero

function zeroCheck(arg1, arg2) {
    var i, argsLen = arguments.length;
    for (i = 0; i <= argsLen; i += 1) {
        if (arguments[i] === 0) {
            // This is where it doesn't behave as I expected
            arguments[i] = 1; // make arg1 = 1
        }
    }
    console.log(arg1); // arg1 = 0
}

zeroCheck(0, 2);

我期待arg1等于1,但它仍然等于0

4

5 回答 5

1

来自 ECMA-262 规范:

"对于非严格模式函数,数组索引(在 15.4 中定义)命名的参数对象的数据属性,其数值名称值小于相应函数对象的形式参数的数量,最初与相应的参数绑定共享它们的值函数的执行上下文。这意味着更改属性会更改参数绑定的相应值,反之亦然。如果这样的属性被删除然后重新定义,或者如果属性被更改为访问器属性,则这种对应关系被破坏。对于严格模式函数,参数对象的属性值只是传递给函数的参数的副本,属性值和形参值之间没有动态链接。”

但是,如果您阅读有关如何设置arguments对象的技术细节,我想您会发现它是基于在调用函数时实际传递给函数的参数数量,而不是声明了多少命名参数,因此使用arguments和循环如果不是全部传入,检查每个命名参数的值可能不起作用。尽管在您的情况下,如果您专门测试0它应该可以工作,因为未传递的参数将是undefined而不是0.

话虽如此,arguments对象的实际行为方式取决于浏览器。Chrome 不遵循规范。

于 2012-08-27T08:57:09.577 回答
1

尽管某些浏览器似乎可以按照您想要的方式工作(Chrome 和 Firefox),但从 ECMAScript 规范中我看不出它总是这样。听起来参数数组可能只是对非严格模式下命名参数的引用,并且它明确表示两者在严格模式下不应相互连接(换句话说,您想要做的是具体不应该在严格模式下工作)。

您可以在这个 jsFiddle http://jsfiddle.net/jfriend00/bG5xp/中看到 Chrome 似乎按照规范描述实现了它。非严格模式下有联动arguments[0]arg1严格模式下没有联动。仔细阅读规范并没有说 javascript 必须在非严格模式下在两者之间建立联系,但它确实让它听起来很可能。如果你想依赖它并且你确定你永远不需要你的代码在严格模式下工作,那么你将不得不测试一堆浏览器来查看你想要的行为是否得到广泛支持。

从规范中也不清楚参数数组是否总是可以修改的,尽管考虑到它是用 javascript 对象(不是实际数组)实现的,这似乎更有可能。

修改参数数组的安全方法是先制作副本并修改副本。当然,这不会修改任何命名参数。如果您愿意,可以手动修改这些。

制作参数数组副本的常用方法是:

var args = Array.prototype.slice.call(arguments, 0);

通常使用arguments数组或命名参数,而不是两者都使用,因为任何命名参数也在参数数组中的已知位置,所以当你修改参数数组时,你真的不需要担心命名参数改变值。

于 2012-08-27T08:28:31.363 回答
1

像这样试试。arg1with value0评估为false/falsy,因此您可以使用此快捷布尔评估

function zeroCheck(arg1,arg2) {
    arg1 = arg1 || 1; 
    console.log(arg1); //=> 1
}

zeroCheck(0,2);

检查所有参数的通用函数(返回一个Array

function zeroCheckArgs(args){
  return [].slice.call(args).map(function(a){return a || 1;});
}

//more conservative
function zeroCheckArgsAlt(args){
  var retArgs = [];
  for (var i=0;i<args.length;i+=1){
    retArgs.push(args[i] || 1);
  }
  return retArgs;
}

function some(){
  var args = zeroCheckArgs(arguments);
  console.log(args);
}

function someAlt(){
  var args = zeroCheckArgsAlt(arguments);
  console.log(args);
}

some(1,0,0,12,12,14,0,1);    //=> [1, 1, 1, 12, 12, 14, 1, 1]
someAlt(1,0,0,12,12,14,0,1); //=> [1, 1, 1, 12, 12, 14, 1, 1]
于 2012-08-27T08:34:35.090 回答
0

它对我有用,检查这个例子小提琴

于 2012-08-27T08:30:10.007 回答
0

@nnnnnn -

“对于非严格模式函数,数组索引(在 15.4 中定义)命名的参数对象的数据属性,其数值名称值小于相应函数对象的形式参数的数量,最初与相应的参数绑定共享它们的值函数的执行上下文。这意味着更改属性会更改参数绑定的相应值,反之亦然。如果这样的属性被删除然后重新定义,或者如果属性被更改为访问器属性,则这种对应关系被破坏。对于严格模式函数,参数对象的属性值只是传递给函数的参数的副本,属性值和形参值之间没有动态链接。”

你的引文实际上回答了我原来的问题。我在下面发布的代码无法按预期工作的原因是因为我实际上使用的是“严格”模式。

// check all arguments, and make sure they aren't zero

function zeroCheck(arg1,arg2) {
    var i, argsLen = arguments.length;
    for (i = 0; i <= argsLen; i += 1) {
        if (arguments[i] === 0) {
            // This is where it doesn't behave as I expected
            arguments[i] = 1; // make arg1 = 1
        }
    }
    console.log(arg1); // arg1 = 0
}

zeroCheck(0,2);

它适用于 xdazz、Jeroen Moons 和 jFriend00 - 因为它们不包括严格: http: //jsfiddle.net/nSJGV/(非严格) http://jsfiddle.net/HDjWx/(严格)

于 2012-08-27T09:20:36.843 回答