(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は結構使うケースが多いのも事実なのですが、これも可能な限り避ける方がよさそうですね。
- Newer: MinibufferがGoogleDocsで干渉する場合がある?
- Older: Flickrがいつの間にか正式版?に
Google Adsense
Social bookmark comment : 0
No comment.
Comment : 0
Trackback : 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」と題したエントリーを書きま...
2007/12/05 (Wed)