LoginSignup
194
174

More than 5 years have passed since last update.

JavaScriptでなぜ Object.create(null) を使うのか?

Last updated at Posted at 2016-11-03

概要

JavaScriptの Object.create(null) はなぜ使われるのか。
{}での初期化とは何が違うのか。

きっかけ

Vuex のソースコードを読んでいて、 Object.create(null) という見慣れない記述を見つけました。
リテラル {} ではいけない理由が気になったので、なぜなのか調べてみました。

スクリーンショット 2016-11-03 午後2.25.52.png

対応ブラウザ

Object.create は Internet Explorer 9 を含めたモダンブラウザで利用可能です。
 
- http://kangax.github.io/compat-table/es5/#test-Object.create
- https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create

Object.create() と {} の違い

MDN - Object.create() によると、 Object.createprototype を指定してオブジェクトを生成する ECMAScript 5 からの仕様のようです。

var a = {}
var b = Object.create(Object.prototype)

この ab は実質同じ挙動になります。

パフォーマンス?

よくある理由として考えたのはパフォーマンスの理由が挙げられます。

ところが調べてみると、リテラルでの生成の方が数倍高速に動作するようです。

※ 2016-11-07追記: リンクを差し替え

スクリーンショット 2016-11-07 午後1.35.19.png

ハッシュとしてのオブジェクトの利用

JavaScriptでオブジェクト使うシーンとして多いのが、ハッシュとしてキャッシュやデータ保存目的で使われるシーンですよね。
気軽に「key-value形式」で保存できるので様々な箇所で使われますが、ユーザーの入力値をキーとして使う場合に問題が出てきます。

例えば、usersというオブジェクトをハッシュのように利用して、ユーザーの入力値(この例では accountnameの値のセット)を保存していく場合を考えてみます。

var users = {} // { アカウント名: 名前 }

function addUser(account, name) {
  // キーが既に登録されていなければ保存
  if (!users[account]) {
    users[account] = name
  }
}

addUser('taro', '山田太郎')
addUser('taro', '田中太郎') // 保存されない

taro というキーははじめて設定するので、値山田太郎は無事に保存できます。
二度目に taro というキーで保存使用すると、既に存在するので無視されます。

では、アカウント名として constructor という厳つい単語を指定をした場合にどうなるでしょうか?

addUser('constructor', '鈴木次郎') // 保存されない

この場合、 users.prototypeconstructorというメソッドを持っているので、登録できないことになってしまいます。

他にも、 toStringvalueOf なども利用できません。

これは、 var users = {} の時点で、 Object.prototypeを引き継いでいるからとなります。

本当に空のオブジェクト

ここで、 Object.create(null) の出番です。

var users = Object.create(null) // { アカウント名: 名前 }

function addUser(account, name) {
  // キーが既に登録されていなければ保存
  if (!users[account]) {
    users[account] = name
  }
}

addUser('taro', '山田太郎')
addUser('constructor', '鈴木次郎') // 保存できる

このように、オブジェクトを Object.create(null) で初期化することで、 Object.prototype を引き継がない「本当に空の」ハッシュとして利用できるようになります。

この仕組みは、ユーザー入力値をキーとして使う場合だけでなく、ライブラリとしてAPIを公開している場合にも活用できます。

冒頭のVuexでObject.create(null)が使われていたのは、ライブラリのAPIとして、ユーザーが自由な名称でメソッドを追加できる仕組みがあるからですね。(actionやmutationなど)

スクリーンショット 2016-11-03 午後3.21.11.png

参考

追記 (2016-11-04)

ハッシュ目的には Map を使えばいいのでは?というコメントをいただきました。

Android 5.1, IE 11から部分的に使えるようですね。

ありがとうございます。

追記 - ObjectとMapの使い分け (2016-11-07)

MDNに Objects and maps compared というセクションがありました。

キーが動的な場合や、任意の型が入る場合、もしくは反復処理をしたい場合には積極的に Map を推奨しているようです。

194
174
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
194
174