JavaScriptのin演算子の理解と使い方
2011/06/03(金) 27:29 Javascript親記事へこのエントリーをはてなブックマークに追加

in演算子の仕様

まずはin演算子の動作を知る。
オブジェクトが指定されたプロパティ(prototypeチェーンを辿って)を持っているかの真偽値を返す
要はhasOwnPropertyとほとんど同じで、違いはprototypeチェーンを辿るかどうか。
in 演算子と obj.hasOwnProperty()の比較は以下を参照
次は仕様書を見てみましょう。
ES3の仕様書:11.8.7 in 演算子 (The in operator)
生成規則 RelationalExpression : RelationalExpression in ShiftExpression は、次のように評価される:
  1. RelationalExpression を評価。
  2. GetValue(Result(1)) を呼出す。
  3. ShiftExpression を評価。
  4. GetValue(Result(3)) を呼出す。
  5. Result(4) がオブジェクトでなければ、例外 TypeError を投げる。
  6. ToString(Result(2)) を呼出す。
  7. Result(4) の HasProperty メソッドを呼び、パラメータに Result(6) を渡す。
  8. Result(7) を返す。
6.までを簡単にまとめると
  String(propName) in objectName
という状態ができる。
右辺はオブジェクトじゃないとTypeErrorだし、
左辺は文字列化したプロパティ名になっている。

そして、次に[[HasProperty]]メソッドを呼ぶとなっている(これがprototypeチェーンを辿る処理にもなってる)
O の [[HasProperty]] メソッド がプロパティ名 P で呼出されると
(ここでは以下のようなイメージ)
> objectName.HasProperty("propName")
次のステップが取られる:
  1. O が名前 P のプロパティを持っていれば、 true を返す。
  2. O の [[HasProperty]] が null ならば、 false を返す。
  3. [[Prototype]] の [[HasProperty]] メソッドをプロパティ名 P で呼出す。
  4. Result(3) を返す。
このステップでprototypeチェーンを辿りながらプロパティ(propName)があるかを調べて返しているという仕様になってる。

in演算子の使い方

in演算子はオブジェクトがプロパティを持っているかを判定できるものだけど、
JavaScriptだとハッシュ的なやり方でプロパティやメソッドがあるかを調べる事もできる。
 if(objectName["propName"]){...}
しかし、この方法だと、次のような場合で意図とは異なる場面に出くわす可能性もある。
(あんまり見たことないけど)
var obj = {
    fuga:false
}
if(obj["fuga"]){//falseが帰ってきてしまうため、意図に反する
    console.log("fugaは存在する");
}
// =>正しく判定するには
if("fuga" in obj){// in演算子を使えば、存在するかを確認できる。
     console.log("fugaは存在する")
}
ただし、このようにin演算子を必要とする場合は多くはないと思います。
次のようなo.xが未定義だったらo.xの値を設定したいとする場合は普通に以下のように書いても問題ないでしょう。
var o = {};
if(!o.x){// o.xはundefinedなので
    o.x = 1;
}
styleプロパティなど、元々の値がundefinedでそれをサポートしているかを判定する場合にin演算子は有用なものになります。
if(document.body.style.zoom){// サポートしていてもデフォルトは空文字
   console.log("zoomをサポートしてる");
}
// こういう時はin演算子
if("zoom" in document.body.style){
    console.log("zoomをサポートしてる");
}
何かほかにおもしろい使い道あったらお願いします。

参考にならない速度比較
ブラウザがサポートしてる機能を調べるのにin演算子を使いやすい気がします。(真偽値で返ってくるため)
サポート状況を調べるのはそう何度もやる必要はないため、上の速度差はそこまで気にするものではないと思います(適材適所)
普段のように、そのプロパティが定義されているかを判定するのにはハッシュを使うのがいいかもしれません(ループで回す場合もあるし)

ES5的なin演算子の利用法については誰かが書いてくれると思いまする。

1: aq 2011年06月03日(金) 深夜3時47分

var a = []; a[9] = 'q'; a.forEach(function() { alert('何回アラートされる?'); });

MDCに載ってるArray.forEach互換コードはinを使って同じ振るまいをしますが、大多数のライブラリのforEachあるいはeachは互換性がありません。


名前:  非公開コメント   

  • TB-URL  http://efcl.info/adiary/0118/tb/