関数の引数を存在確認するための高速化Tips

(2007/12/12 追記)内容をまとめ直し+再考しました。

JavaScriptで関数の引数チェック行う場合に、「どんなチェック方法が速いのか?」な話。

たとえば、引数が存在する場合は「その引数」を、存在しない場合は「bar」を返す、という場面を想定します。単純に考えるとこんな感じ。

function check(arg){
if(arg) {
return arg;
} else {
return 'bar';
}
}

うーん、nullチェックをする、って方法も考えられます。

function check(arg){
if(arg != null){
return arg;
} else {
return 'bar';
}
}

typeof で確認って方法もありますね。

function check(arg){
if(typeof arg != 'undefined'){
return arg;
} else {
return 'bar';
}
}

条件を限定して、引数が「foo」の場合はfooを返す、という場合はこう書けます。

function check(arg){
if(arg=='foo'){
return arg;
} else {
return 'bar';
}
}

と、引数確認だけでもパっと思いついただけでも、これだけ思いつきます。(もっと全然違うパターンがあるよ!な場合はTBかコメントで教えてください!)

あと、もっと突っ込むとif文ではなく、三項演算子を使うとワンライナーでも書けてしまいます。たとえば一番最初の場合だと

function check(arg){
return arg || 'bar';
}

こんな感じに。(2007/12/05 15:00追記:この場合はワンライナーで書いてるけども、三項演算子を利用しているわけではないですね)

どう書けば速いの?

単純に疑問に思ったので、ざっとテストコードを書いてベンチマーク取ってみました。検証コードはこちら。

 

function checkStrNoIf(arg){
return (arg=='foo')? arg : 'bar';
}

function checkStrIf(arg){
if(arg=='foo'){
return arg;
} else {
return 'bar';
}
}


function checkArgsNoIf(arg){
return arg || 'bar';
}

function checkArgsIf(arg){
if(arg) {
return arg;
} else {
return 'bar';
}
}


function checkNullNoIf(arg){
return (arg!=null)? arg : 'bar';
}

function checkNullIf(arg){
if(arg != null){
return arg;
} else {
return 'bar';
}
}


function checkTypeNoIf(arg){
return (typeof(arg) != 'undefined')? arg : 'bar';
}

function checkTypeIf(arg){
if(typeof arg != 'undefined'){
return arg;
} else {
return 'bar';
}
}


// logging
function log(){
//return console.log.apply(this, arguments);
return print.apply(this, arguments);
}

// bench
var s, e;
var c = 100000;

s = new Date();
for(var i=0; i<c; i++){
checkStrNoIf();
}
e = new Date();
log("[checkStrNoIf]" + (e-s));


s = new Date();
for(var i=0; i<c; i++){
checkStrIf();
}
e = new Date();
log("[checkStrsIf]" + (e-s));


s = new Date();
for(var i=0; i<c; i++){
checkArgsNoIf();
}
e = new Date();
log("[checkArgsNoIf]" + (e-s));

s = new Date();
for(var i=0; i<c; i++){
checkArgsIf();
}
e = new Date();
log("[checkArgsIf]" + (e-s));


s = new Date();
for(var i=0; i<c; i++){
checkNullNoIf();
}
e = new Date();
log("[checkNullNoIf]" + (e-s));


s = new Date();
for(var i=0; i<c; i++){
checkTypeNoIf();
}
e = new Date();
log("[checkTypeNoIf]" + (e-s));

 

要するに、冒頭で上げた4ケースにそれぞれif文を使う場合、使わない場合でそれぞれ10万回ループで回して実行時間を比較。検証環境はFedora7上のSpiderMonkeyで。Firefox2上での比較、と考えてほぼ問題ないと思います。(SpiderMonkeyって何ぞや?とかインストール方法とかはまた別記事で書きます)

実行と検証

実行結果はこんな感じになりました。

$ js -f args.js
[checkStrNoIf]522
[checkStrIf]541
[checkArgsNoIf]538
[checkArgsIf]533
[checkNullNoIf]538
[checkTypeNoIf]592

なかなか面白い結果になっています。ざっくりまとめるとこんな感じ。

  • if文を使うより三項演算子の方が高速
  • typeofで比較する場合は三項演算子の方が顕著に高速
  • 文字列比較できる場合は、素直に文字列比較した方が良い
  • 文字列比較<引数確認<null確認<typeof確認
  • typeof確認はコストが大きい

まとめ

三項演算子ってif文のエイリアスみたいなもんだと思ってた。中身は等価というか。結構露骨に速度に関わってくるのが意外ですねぇ。コード読みづらくなるケースが多いけど、可能な限りで積極的に使っちゃっていいのかもしれません。三項演算子++

あと、typeofは結構使うケースが多いのも事実なのですが、これも可能な限り避ける方がよさそうですね。

関連広告

Trackbacks:2

TrackBack URL for this entry
http://blog.katsuma.tv/mt-tb.cgi/103
Listed below are links to weblogs that reference
関数の引数を存在確認するための高速化Tips from blog.katsuma.tv
if文と三項演算子 from Pa works very hard 2007-12-06 (木) 21:49
カツマさんのところで、javascriptのif文と三項演算子の速度比較をされたようです。 三項演算子の方が速い場合が多い理由(の予想) if...
変数の存在を確認する方法(その2) from blog.katsuma.tv 2007-12-12 (水) 02:26
前回に「関数の引数を存在確認するための高速化Tips」と題したエントリーを書きま...

Home > Javascript > 関数の引数を存在確認するための高速化Tips

Search
Feeds

Return to page top