質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.85%

  • JavaScript

    14204questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Node.js

    1608questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。

ES6に対応したObject型のインスタンスかどうかを判定する方法

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 393

murabito

score 14

 やりたいこと

JavaScriptでObject型のインスタンスなのかどうかを判定したい。

 質問

function isObject(value) {
    return value !== null && typeof value !== 'undefined' && typeof value === 'object' && !Array.isArray(value);
}

console.log(isObject({}) // true
console.log(isObject([]) //false
console.log(isObject(null)) //false
console.log(isObject(undefined)) //false
console.log(isObject(new Date())) //true
console.log(isObject(new Map())) //true


こんな感じの関数を作ればObject型のインスタンスかどうかを判定できるかなと思ったのですが、関数を適用する対象がMap型のインスタンスやDate型のインスタンス等の場合、これでは上手く判定出来ませんでした。

なので、constructor.nametoString()の値を比較してあげれば良いのかなと思い、
得られる値を確認するため、以下のようなデバッグコードを書いて実行してみました。

function debug(value) {
    console.log('value: ', value);
    value != null && console.log('constructor.name: ', value.constructor.name);
    console.log('toString: ', Object.prototype.toString.call(value));
    console.log('==================');
}

debug({});
debug(new Proxy({}, {}));
debug(function(){});
debug(new Proxy(function(){}, {}));
debug([]);
debug(new Proxy([], {}));
debug(new Map());
debug(new Proxy(new Map(), {}));
debug(new WeakMap());
debug(new Proxy(new WeakMap(), {}));
debug(new Set());
debug(new Proxy(new Set(), {}));
debug(new WeakSet());
debug(new Proxy(new WeakSet(), {}));
debug(Symbol('symbol'));
debug(null);
debug(undefined);
debug((function(){ return arguments; })());
debug(new Date());

 ログ

value:  {}
constructor.name:  Object
toString:  [object Object]
==================
value:  Proxy {}
constructor.name:  Object
toString:  [object Object]
==================
value:  ƒ (){}
constructor.name:  Function
toString:  [object Function]
==================
value:  ƒ anonymous()
constructor.name:  Function
toString:  [object Function]
==================
value:  []
constructor.name:  Array
toString:  [object Array]
==================
value:  Proxy {length: 0}
constructor.name:  Array
toString:  [object Array]
==================
value:  Map(0) {}
constructor.name:  Map
toString:  [object Map]
==================
value:  Proxy {}
constructor.name:  Map
toString:  [object Map]
==================
value:  WeakMap {}
constructor.name:  WeakMap
toString:  [object WeakMap]
==================
value:  Proxy {}
constructor.name:  WeakMap
toString:  [object WeakMap]
==================
value:  Set(0) {}
constructor.name:  Set
toString:  [object Set]
==================
value:  Proxy {}
constructor.name:  Set
toString:  [object Set]
==================
value:  WeakSet {}
constructor.name:  WeakSet
toString:  [object WeakSet]
==================
value:  Proxy {}
constructor.name:  WeakSet
toString:  [object WeakSet]
==================
value:  Symbol(symbol)
constructor.name:  Symbol
toString:  [object Symbol]
==================
value:  null
toString:  [object Null]
==================
value:  undefined
toString:  [object Undefined]
==================
value:  Arguments [callee: ƒ, Symbol(Symbol.iterator): ƒ]
constructor.name:  Object
toString:  [object Arguments]
==================
value:  Wed May 09 2018 17:06:26 GMT+0900 (JST)
constructor.name:  Date
toString:  [object Date]
==================

実行結果を見る限りだと、constructor.nameよりはtoString()の値の方が信頼出来そうに感じたのですが、
以下のようなコードでObject型のインスタンスかどうかを判定するのは安全、かつ、確かでしょうか?

function isObject(value) {
    // return value !== null && typeof value !== 'undefined' && Object.prototype.toString.call(value) === '[object Object]';

    //  nullかundefinedのチェックも不要になったので消します
    return Object.prototype.toString.call(value) === '[object Object]';
}

 注釈

尚、new Proxy({}, {})とした場合も[object Object]となりますが、これはisObject()の結果がtrueであって構いません。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • think49

    2018/05/10 00:58

    そもそも、「Object型のインスタンス」の定義は何ですか。

    キャンセル

  • think49

    2018/05/10 09:08

    それから、「判定する目的」は何ですか。判定した先に何をさせたいのですか。安全性を気にされていますが、視点次第でリスクはあるので、全てにおいて安全はあり得ません。あなたの目的に最もマッチする方法を選択する必要があります。

    キャンセル

  • murabito

    2018/05/11 20:21

    すみません。言われてみると何を目的としてこの判定をしたいのか考えていませんでした。

    キャンセル

回答 2

checkベストアンサー

+3

この条件では、function Foo()からnew Fooとしたオブジェクトに対してもtrueを返しますが、それで問題ないでしょうか。

自分でなにか作るとしたら、プロトタイプのオブジェクトを比較する、というのがいいかなと思いました。

function isObject(obj) {
  return obj && Object.getPrototypeOf(obj) === Object.prototype
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/09 17:58

    ご指摘ありがとうございます。確かにnew function(){}はオブジェクトになってしまいますね。盲点でした。

    キャンセル

+1

toStringTagを使えば、あなたオリジナルのタグを設定することができます。
Symbol.toStringTag - JavaScript | MDN

とのことなので、そのクラスの実装によるのではないでしょうか。
とりあえず、ビルトインオブジェクトで想定と異なりそうなものを見つけましたので、お知らせいたします。

  function isObject(value) {
    return Object.prototype.toString.call(value) === '[object Object]';
  }
  isObject(Intl); //true

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/05/10 00:13

    リンク先を読むと、クラスのインスタンスのデフォルトタグもobject Objectなのですね。こちらも盲点でした。カスタマイズも自由に出来るとなると、toString()は今回の目的に対して信頼できる値は返さないようですね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.85%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • JavaScript

    14204questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • Node.js

    1608questions

    Node.jsとはGoogleのV8 JavaScriptエンジンを使用しているサーバーサイドのイベント駆動型プログラムです。