【JavaScript】オブジェクトが空かどうか判定する

 Arrayでは、lengthの値を調べることによって空かどうかを判定することができますが、今回はObject(連想配列)が空かどうかを判定する方法を探ってみます。

空かどうかの判定方法

Object.keys(obj).lengthを使う

 おそらく、最もポピュラーな方法が、Objectのkeys配列を取得することによって判定する方法です。

function isEmpty(obj){
  return !Object.keys(obj).length;
}

console.log(isEmpty({}));        // -> true
console.log(isEmpty({"a":"a"}));  // -> false

for~inを使う

 上述した、Object.keys().lengthを使う方法は、Chromeのバージョンによっては極端に速度が劣化(1.5倍程度)します。

 現行のものは既に修正されているようですが、古いバージョンに対応しなければならなくなったときは以下を使ってください。

function isEmpty(obj){
  for(let i in obj){
    return false;
  }
  return true;
}

console.log(isEmpty({}));        // -> true
console.log(isEmpty({"a":"a"}));  // -> false

 おそらく、以前のChrome(50以前で確認)では、keysメソッドで毎回列挙する処理が走っていたものと思われます。もしかすると他のブラウザでも速度劣化が見られるかもしれません。

(おまけ)無理矢理やってみる

 こんなこともできますね。

function isEmpty(obj){
  return JSON.stringify(obj) === "{}";
}

console.log(isEmpty({}));        // -> true
console.log(isEmpty({"a":"a"}));  // -> false

 ただし低速です。

パフォーマンス計測

function isEmptyKeysLength(obj){
  return !Object.keys(obj).length;
}

function isEmptyJSON(obj){
  return JSON.stringify(obj) === "{}";
}

function isEmptyForIn(obj){
  for(let i in obj){
    return false;
  }
  return true;
}

function calcPerf(name, obj, fn){
  console.time(name);
  for(let i = 0; i < 100; i++){
    fn(obj);
  }
  console.timeEnd(name);
}

var obj = {};
for(let i = 0; i < 100000; i++){
  obj[String.fromCharCode(i)] = true;
}

calcPerf("keys.length", obj, isEmptyKeysLength);
calcPerf("forIn", obj, isEmptyForIn);
calcPerf("JSON.stringify", obj, isEmptyJSON);
keys().length for~in JSON.stringify
2399.83ms 2441.23ms 3595.88ms

 これを見ると、普通に使うにはkeysが最も簡潔かつ、適しているように見えますね。

まとめ

 普通に判定するだけなら、Object.keys().lengthを使うのがよさそうです。見通しのよいコードを書くためにも、シンプルな判定方法を実装しましょう。