web-dev-qa-db-ja.com

JavaScriptでNaNを破る

NaN伝播で例外を発生させる(つまり、NaNに数値を乗算または追加する)、またはそうするように構成できる最新のブラウザーはありますか?

サイレントNaNの伝播は、ひどく陰湿なバグの原因であり、パフォーマンスが低下した場合でも、早期に検出できるようにしたいと考えています。


use strictjshint etal。のバグの例を次に示します。拾わない:

object = new MyObject();
object.position.x = 0;
object.position.y = 10;

// ... lots of code

var newPosition = object.position + 1; // <- this is an error, and should
                                       //    have been object.position.x
                                       //    however it fails *silently*,
                                       //    rather than loudly

newPosition *= 2;                      // <- this doesn't raise any errors either.
                                       //    this code is actually ok if the
                                       //    previous line had been correct
48
kibibu

尋ねられた質問に答えるには:

NaN伝播で例外を発生させる(つまり、NaNに数値を乗算または追加する)、またはそうするように構成できる最新のブラウザーはありますか?

いいえ。Javascriptは非常に寛容な言語であり、Math.PIに 'potato'を掛けてもかまいません(ヒント:NaNです)。これは、私たちの開発者が対処しなければならない言語の悪い部分(またはあなたの見方によっては良い部分)の1つにすぎません。

この質問をしているバグに対処する(おそらく)、オブジェクトでゲッターとセッターを使用することは、これを強制し、このような間違いを防ぐための1つの確実な方法です。

37
Rob M.

以下のコードが役立つ場合があります。

この問題を完全に解決するには、operator reloadのようなものが必要だと思います。 '+-/ *'のような演算子をリロードし、オペランドが数値であるかどうかを確認し、そうでない場合はエラーをスローします。

部分的な解決策として、JavaScriptが 'a + b'のような操作を行うと、Object.prototypeから継承するvalueOfメソッドが呼び出され、Object.prototype.valueOfを書き換えることができます。

Object.prototype.originalValueOf = Object.prototype.valueOf;

Object.prototype.valueOf = function() {
  if (typeof this !== 'number') {
    throw new Error('Object is not a Number');
  }

  return this.originalValueOf();
}

var a = 1 + 2; // -> works
console.log(a); // -> 3

var b = {};
var c = b + 2; // -> will throw an Error

(ヒント:本番環境でコードを削除して、開発環境に追加できます。)

26
Jerry

これを行う最もクリーンな方法は、式の結果を毎回検証する短い便利な関数を使用することです。

私はそれがあなたが探している答えではないことを知っていますが、これはjavascriptの性質であり、悲しいことにそれを変更することはできません

function v(a){ if(isNaN(a)) throw "error"; return a; }
var test = v(100 * "abc");
10
user652649

ゲッターとセッターが重宝する状況だと思います。

以下は、アイデアを提供するための擬似コードの例です。

//Inside your Object class code.
function getPosition() {

  //You don't want the property "position" to be NaN, right?
  if(isNaN(this.position)) 
    throws "NaN is not a correct numerical value!";

  return this.position;

}


//Somewhere in your code
var newPosition = object.getPosition() + 1; //raises an exception.

これは、偽の演算子のオーバーロードを実装して事態をより複雑にするよりも優れていると思います。

2
Jason

これは古いスレッドだと思いますが、あなたの質問に対する非常に簡単な答えがあるかもしれません。以下のステートメントの関数を作成するか、インラインで追加することができます。

JavaScriptには、特定の値に対していくつかの固有の動作があります。これらのユニークな動作の1つは、非数値またはNaNを中心に展開します。 NaNの値は、NaN自体を含む他の値と比較されません。このため、次のステートメントがあります。

if(x != x) {
    throw "Value is NaN!";
}

true if and only ifxの値がNaNである場合にのみ当てはまります。

2
War10ck