一部のリテラルでinstanceofがfalseを返すのはなぜですか?


284
"foo" instanceof String //=> false
"foo" instanceof Object //=> false
true instanceof Boolean //=> false
true instanceof Object //=> false
false instanceof Boolean //=> false
false instanceof Object //=> false

// the tests against Object really don't make sense

配列リテラルとオブジェクトリテラルが一致しています...

[0,1] instanceof Array //=> true
{0:1} instanceof Object //=> true

なぜ全部ではないのですか?または、なぜすべてではないのですか?
そして、それらのインスタンスは何ですか?

FF3、IE7、Opera、Chromeでも同じです。したがって、少なくとも一貫しています。


いくつか逃した。

12.21 instanceof Number //=> false
/foo/ instanceof RegExp //=> true

回答:


424

プリミティブは、Javascript内から作成されたオブジェクトとは異なる種類のタイプです。MozillaのAPIドキュメント

var color1 = new String("green");
color1 instanceof String; // returns true
var color2 = "coral";
color2 instanceof String; // returns false (color2 is not a String object)

コードでプリミティブ型を構築する方法を見つけることができません。おそらくそれは不可能です。これがおそらく人々がのtypeof "foo" === "string"代わりに使用する理由ですinstanceof

このようなことを覚える簡単な方法は、「何が正気で簡単に学べるのだろう」と自分に問うことです。答えが何であれ、JavaScriptは他のことを行います。


5
JavaScriptを嫌う新しい理由がある毎日は良い日です。長い間遅れていることは承知していますが、この投稿をありがとうございます。
toniedzwiedz

57
あなたの用語は間違っています。「リテラル」という言葉は、コンストラクタを使用せずにデータを作成するための構文を指します。結果のデータは参照しません。リテラル構文を使用して、オブジェクトと非オブジェクトの両方を作成できます。正しい用語は「プリミティブ」で、非オブジェクトデータを指します。一部のデータには、プリミティブ表現とオブジェクト表現の両方があります。文字列はそれらのタイプのデータの1つです。
灰色の状態が2012

14
参考までに、リテラル構文なしでプリミティブを作成できます。(new String()).valueOf();
灰色の状態が2012

11
typeof foo === 'string'それだけでは不十分です。axkibeの回答を参照してください。
ブライアンラーセン2013年

1
さらに、typeof new String('')返品"object"
トランザング

105

私が使う:

function isString(s) {
    return typeof(s) === 'string' || s instanceof String;
}

JavaScriptでは文字列がリテラルまたはオブジェクトになる可能性があるためです。


28
ところで何かが見つかりました。function isString(s) { return s.constructor === String; }リテラルおよび文字列オブジェクト(少なくともV8では)で機能します
axkibe

7
お奨めJavaScriptが大好きです。
Derek━會功夫2014

2
可能な場合は、jQuery.type(s)=== 'string'(api.jquery.com/jquery.type)、jQuery.isArray()、jQuery.isFunction()、jQuery.isNumeric()を使用しています。
Ivan Samygin 2014

1
あなたが正しいしている間@axkibeは、それはだパフォーマンスとほぼないようにtypeof
Qix-モニカは2015

typeof "?"を使用できます == String.name.toLowerCase()[しかし、なぜ[] instanceof Arrayなのか?]
QuentinUK

62

JavaScriptでは、プリミティブ(ブール値、null、数値、文字列、および値undefined(およびES6のシンボル))を除いて、すべてがオブジェクトです(または少なくともオブジェクトとして扱われます)。

console.log(typeof true);           // boolean
console.log(typeof 0);              // number
console.log(typeof "");             // string
console.log(typeof undefined);      // undefined
console.log(typeof null);           // object
console.log(typeof []);             // object
console.log(typeof {});             // object
console.log(typeof function () {}); // function

オブジェクトを見るとわかるように、配列と値nullはすべてオブジェクトと見なされます(null存在しないオブジェクトへの参照です)。関数は、呼び出し可能なオブジェクトの特殊なタイプであるため、区別されます。ただし、それらはまだオブジェクトです。

一方リテラルtrue0""およびundefinedオブジェクトではありません。これらはJavaScriptのプリミティブな値です。ただし、ブール値、数値、および文字列にもコンストラクターBooleanNumberありString、それぞれのプリミティブをラップして追加の機能を提供します。

console.log(typeof new Boolean(true)); // object
console.log(typeof new Number(0));     // object
console.log(typeof new String(""));    // object

ご覧のとおり、プリミティブ値がBooleanNumberおよびStringコンストラクター内でそれぞれラップされると、それらはそれぞれオブジェクトになります。instanceofオペレータは(それが返す理由であるオブジェクトのために働くfalseプリミティブ値のために):

console.log(true instanceof Boolean);              // false
console.log(0 instanceof Number);                  // false
console.log("" instanceof String);                 // false
console.log(new Boolean(true) instanceof Boolean); // true
console.log(new Number(0) instanceof Number);      // true
console.log(new String("") instanceof String);     // true

両方typeofを見ることができinstanceof、値がブール値、数値、または文字列かどうかをテストするには不十分であるtypeofため、プリミティブブール値、数値、および文字列に対してのみ機能します。またinstanceof、プリミティブなブール値、数値、文字列では機能しません。

幸い、この問題には簡単な解決策があります。のデフォルト実装toString(つまり、でネイティブに定義されているObject.prototype.toString)は、[[Class]]プリミティブ値とオブジェクトの両方の内部プロパティを返します。

function classOf(value) {
    return Object.prototype.toString.call(value);
}

console.log(classOf(true));              // [object Boolean]
console.log(classOf(0));                 // [object Number]
console.log(classOf(""));                // [object String]
console.log(classOf(new Boolean(true))); // [object Boolean]
console.log(classOf(new Number(0)));     // [object Number]
console.log(classOf(new String("")));    // [object String]

[[Class]]値の内部プロパティは、値よりもはるかに便利ですtypeof。を使用Object.prototype.toStringして、typeof次のように独自の(より便利な)演算子のバージョンを作成できます。

function typeOf(value) {
    return Object.prototype.toString.call(value).slice(8, -1);
}

console.log(typeOf(true));              // Boolean
console.log(typeOf(0));                 // Number
console.log(typeOf(""));                // String
console.log(typeOf(new Boolean(true))); // Boolean
console.log(typeOf(new Number(0)));     // Number
console.log(typeOf(new String("")));    // String

この記事がお役に立てば幸いです。プリミティブとラップされたオブジェクトの違いについて詳しく知るには、次のブログ投稿を読んでください。JavaScriptプリミティブの秘密の生活


6
+1、altoughがnullあるプリミティブ値(のみだけでなくtypeof、オペレータが混乱されている)
Bergi

33

あなたはコンストラクタプロパティを使用することができます:

'foo'.constructor == String // returns true
true.constructor == Boolean // returns true

18
変数をテストするとき、この手法は特定の状況で失敗する可能性があることに注意してください。現在のウィンドウへの暗黙的な参照は、目の前にあるStringBoolean、上記の例では、あなたがテストしているそうだとすればconstructor、それはします(ポップアップまたはフレームのような)別のウィンドウで作成された文字列変数のプロパティをいない単にに等しいことString、それがされますに等しくなるthatOtherWindowsName.String
Michael Mathews、

そして、instanceofはこれを処理せず、適切なブール結果を返しませんか?
Chris Noe

5
Stringの子孫を渡された場合、これは失敗します。
ブライアンラーセン

1
@MichaelMathews:その救済にこの作品:Object.prototype.toString.call('foo') === '[object String]'
rvighne

@BryanLarsenおよび@MichaelMathewsの使用に問題はありますd.constructor == Stringか?たとえば、緩やかな等価演算子を使用します。
dotnetCarpenter 2016年

7
 typeof(text) === 'string' || text instanceof String; 

あなたはこれを使うことができます、それは両方のケースで機能します

  1. var text="foo"; // typeofが機能します

  2. String text= new String("foo"); // instanceofは機能します


3

これはECMAScript仕様のセクション7.3.19ステップ3で定義されています。If Type(O) is not Object, return false.

つまり、Objin Obj instanceof Callableがオブジェクトでない場合、は直接instanceofショートしfalseます。


1

私は実行可能な解決策を思いついたと思います:

Object.getPrototypeOf('test') === String.prototype    //true
Object.getPrototypeOf(1) === String.prototype         //false

-1

https://www.npmjs.com/package/typeof

instanceof(コンストラクタ名)の文字列表現を返します

function instanceOf(object) {
  var type = typeof object

  if (type === 'undefined') {
    return 'undefined'
  }

  if (object) {
    type = object.constructor.name
  } else if (type === 'object') {
    type = Object.prototype.toString.call(object).slice(8, -1)
  }

  return type.toLowerCase()
}

instanceOf(false)                  // "boolean"
instanceOf(new Promise(() => {}))  // "promise"
instanceOf(null)                   // "null"
instanceOf(undefined)              // "undefined"
instanceOf(1)                      // "number"
instanceOf(() => {})               // "function"
instanceOf([])                     // "array"

-2

私によって引き起こされた混乱

"str".__proto__ // #1
=> String

したがって、istanceofが以下のように機能するため、"str" istanceof String戻りtrueます。

"str".__proto__ == String.prototype // #2
=> true

#1#2の結果は互いに矛盾するため、どちらかが間違っているはずです。

#1は間違っている

私はそれ__proto__が非標準のプロパティによって引き起こされていることを理解しているので、標準のプロパティを使用します:Object.getPrototypeOf

Object.getPrototypeOf("str") // #3
=> TypeError: Object.getPrototypeOf called on non-object

これで、式#2#3の間に混乱がなくなりました。


2
#1は正しいですが、それはプロパティアクセサーが原因です。これは、Object("str").__proto__またはと同様に、プリミティブ値をそれぞれのオブジェクトタイプにボックス化しますObject("str") instanceof String
Jonathan Lonowski、2015年

@JonathanLonowskiこれを指摘してくれてありがとう。私はそれを知りませんでした
mko

-8

または、次のように独自の関数を作成することもできます。

function isInstanceOf(obj, clazz){
  return (obj instanceof eval("("+clazz+")")) || (typeof obj == clazz.toLowerCase());
};

使用法:

isInstanceOf('','String');
isInstanceOf(new String(), 'String');

これらは両方ともtrueを返すはずです。


14
evalが表示されます。悪の。
Aaria Carter-Weir
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.