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

一部のブラウザー(ChromeおよびFirefox)は希望どおりに動作しているように見えますが、ECMAScript仕様からは、常にこのように動作することは明らかではありません。これは、arguments配列がおそらく非厳密モードでの名前付き引数への単なる参照であるように聞こえ、厳密モードでは2つが互いに接続してはならないことを具体的に示しています(言い換えると、具体的には厳密モードでは動作しないはずです)。

このjsFiddlehttp : //jsfiddle.net/jfriend00/bG5xp/で、Chromeが仕様に記載されているとおりに実装しているように見えることがわかります。arguments[0]非厳密モードではとの間arg1にリンクがあり、厳密モードではそれらの間にリンクはありません。仕様を注意深く読んでも、JavaScriptが非厳密モードで2つの間にリンクを張る必要があるとは言えませんが、それは可能性が高いように聞こえます。これに依存したい場合で、コードを厳密モードで動作させる必要がないと確信している場合は、多数のブラウザーをテストして、目的の動作が広くサポートされているかどうかを確認する必要があります。

また、引数配列が常に変更可能であるかどうかも仕様から明らかではありませんが、実際の配列ではなく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 に答える
1

ECMA-262仕様から:

"非厳密モード関数の場合、数値名の値が対応する関数オブジェクトの仮パラメーターの数よりも少ない引数オブジェクトの配列インデックス(15.4で定義)の名前付きデータプロパティは、最初にそれらの値を対応する引数バインディングと共有します。関数の実行コンテキスト。これは、プロパティを変更すると、引数バインディングの対応する値が変更されることを意味します。その逆の場合、このようなプロパティが削除されてから再定義されるか、プロパティがアクセサプロパティに変更されると、この対応は壊れます。厳密モードの場合関数の場合、argumentsオブジェクトのプロパティの値は、関数に渡される引数のコピーであり、プロパティ値と仮パラメータ値の間に動的なリンクはありません。」

しかし、オブジェクトの設定方法の技術的な詳細を読むargumentsと、宣言された名前付き引数の数ではなく、呼び出されたときに実際に関数に渡される引数の数に基づいていることがわかると思います。したがってarguments、ループを使用します。名前付き各パラメーターの値をチェックすることは、すべてが渡されていない場合は機能しない可能性があります。ただし、特にテストしている場合は、渡されていないパラメーターがではなく機能するため、機能0するはずです。undefined0

そうは言っても、argumentsオブジェクトが実際にどのように動作するかはブラウザによって異なります。Chromeは仕様に準拠していません。

于 2012-08-27T08:57:09.577 に答える
0

それは私のために働きます、この例のフィドルをチェックしてください

于 2012-08-27T08:30:10.007 に答える
0

@nnnnnn-

「非厳密モード関数の場合、数値名の値が対応する関数オブジェクトの仮パラメーターの数よりも少ない引数オブジェクトの配列インデックス(15.4で定義)の名前付きデータプロパティは、最初にそれらの値を対応する引数バインディングと共有します。関数の実行コンテキスト。これは、プロパティを変更すると、引数バインディングの対応する値が変更されることを意味します。その逆の場合、このようなプロパティが削除されてから再定義されるか、プロパティがアクセサプロパティに変更されると、この対応は壊れます。厳密モードの場合関数の場合、argumentsオブジェクトのプロパティの値は、関数に渡される引数のコピーであり、プロパティ値と仮パラメータ値の間に動的なリンクはありません。」

あなたの引用は実際に私の最初の質問に答えます。以下に掲載されている私のコードが期待どおりに機能しない理由は、実際に「厳密な」モードを使用していたためです。

// 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で機能しました-strictが含まれていなかったため:http://jsfiddle.net/nSJGV/ non-strict) http://jsfiddle.net/HDjWx/(strict)

于 2012-08-27T09:20:36.843 に答える