RegExp#test,RegExp#execの引数にundefinedやnullを渡すと文字列として扱われる

みたいです。ショック。例えば先頭に英小文字を含むかどうかを調べる時、

var str;
/^([a-z])/.exec(str);  // testでも同様

とすると、
strがundefinedのときはRegExp.$1 = "u"("undefined"の先頭)、
strがnullのときはRegExp.$1 = "n"("null"の先頭)
となり、有効な値が入っていないつもりだったのにマッチに成功してしまいます。

strがundefinedやnullのときにエラーになるので、Javaの"pattern".equals(str)と同じ発想でRegExp.execを使っていたのですが、全て見直しが必要となってしまいました(´・ω・`)ショボーン

id:amachangさんにコメントをいただきました!

RegExp.prototype._exec = RegExp.prototype.exec;
RegExp.prototype.exec = function(s) { if(!s) throw Error(’ileagal argument’); return this._exec.apply(this, arguments) };
こんな感じでどうですか? ^^
if(!s)のところは適当に書き換えてみてください。

コメントありがとうございます!なるほど、元の関数を置き換えちゃえ、ということですね。どうやらこの挙動は仕様のようですね。。。
ちょびっとだけ調べてみたんですが

regexp がその Class プロパティが "RegExp" であるオブジェクトでないならば、それは式 new RegExp(regexp) の結果に置換される。

ということで、new RegExp(undefined),new RegExp(null)はどうなるかというと

new RegExp(undefined)
/undefined/

new RegExp(null)
/null/

とそれぞれこのような正規表現になってしまいます。This Document has Movedにundefined,nullに関しての記述が無いせい、なのかな?「ToString(string) の値とする」としか書いてないからそれぞれ文字列として扱われる、と。。。

結局、マッチ対象の文字列がundefinedやnullの場合に誤動作を起こさないためには

  • id:amachangさんの方法のように、RegExp#test,RegExp#execをundefined,nullをはじくように書き換える
  • RegExp#test,RegExp#execの前にif文でundefined,nullをはじく
  • String#matchを使う

の3つの選択肢から選ばないといけないようですね。ちょっとすっきり(`・ω・´)シャキーン