JavaScriptのinstanceof演算子とは何ですか?


313

instanceofJavaScript のキーワードは、JavaScriptはオブジェクト指向プログラミング言語ではないと考える傾向があるため、最初に遭遇したときは非常に混乱する可能性があります。

  • それは何ですか?
  • それはどのような問題を解決しますか?
  • いつそれが適切でいつ適切でないのですか?

3
以下の答えは非常に役立ちますが、実際の単語のアプリケーションではあまり使用しません(少なくとも私は使用しません)。文字列を保持してそれをチェックするobject.typeプロパティを作成します。
Omar Al-Ithawi、2012年

4
JSはまったく意味がありません:"foo" instanceof String=> false、1 instanceof Number=> false、{} instanceof Object=> false。何だって?!
morbusg 2013年

12
@morbusgあなたのコメントは誤解を招くものです。最初"foo" instanceof String => falseは正しいですtypeof "foo" == 'string'new String("foo") instanceof String => true、なぜならtypeof String == 'function'-あなたはクラス(クラスの定義)のように関数を扱うべきです。として割り当てると、変数はinstanceof一部function(クラス)になりますvar v = new AnythingWhatTypeofEqualsFunction()。同じことがにも当てはまります1typeof 1 == 'number'- 「number」は「関数」ではありません:)次- {} instanceof ObjectあるTRUEノードと現代のブラウザで
fider

1
@fider:それはルビイストから来た言語仕様への解説でした。
morbusg 2013

@morbusg- ({}) instanceof Object戻りtrueます。実際、作成したコードはエラーになります。
DDM

回答:


279

instanceof

左側(LHS)オペランドは、クラスの実際のコンストラクターである右側(RHS)オペランドに対してテストされる実際のオブジェクトです。基本的な定義は次のとおりです。

Checks the current object and returns true if the object
is of the specified object type.

ここにいくつかの良い例があり、Mozillaの開発者サイトから直接取られた例があります

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

言及する価値があることの1つはinstanceof、オブジェクトがクラスのプロトタイプから継承した場合にtrue と評価されることです。

var p = new Person("Jon");
p instanceof Person

p instanceof Personからp継承するので、それは事実Person.prototypeです。

OPの要求ごと

サンプルコードと説明を含む小さな例を追加しました。

変数を宣言するときは、特定の型を指定します。

例えば:

int i;
float f;
Customer c;

上記のあなたにいくつかの変数を示し、すなわちifc。タイプはintegerfloatおよびユーザー定義のCustomerデータタイプです。上記のようなタイプは、JavaScriptだけでなく、どの言語にも対応できます。ただし、JavaScriptでは、変数を宣言するときに型を明示的に定義しないためvar x、xは数値/文字列/ユーザー定義のデータ型になる可能性があります。それで何をするかinstanceofというと、オブジェクトをチェックして、それが指定されたタイプであるかどうかを確認しますCustomer

var c = new Customer();
c instanceof Customer; //Returns true as c is just a customer
c instanceof String; //Returns false as c is not a string, it's a customer silly!

上記ではc、型で宣言されていることがわかりましたCustomer。私たちはそれを新しくして、それがタイプかどうかをチェックしましたCustomer。確かに、trueを返します。次に、引き続きCustomerオブジェクトを使用して、それがであるかどうかを確認しますString。いいえ、間違いなく、オブジェクトではなくオブジェクトStringを新しくしました。この場合、falseを返します。CustomerString

本当に簡単です!


@Alon-私はあなたのために例を追加しました。上記を参照してください。color1は文字列型であるため、color1は文字列であるため、color1 instanceof String;trueを返します。
JonH 2010年

@Alon-オブジェクトをチェックして、オブジェクトのタイプを確認します。人/顧客オブジェクトを検討してください。つまり、person p = new person()pは人物型であり、文字列型ではありません。
JonH 2010年

JavaScriptでは、変数がその存続期間を通して異なる型を持つ柔軟性を持っていることを理解するのは難しいかもしれません。コード例:jsfiddle.net/sikusikucom/znSPv
moey

@ Siku-Siku.Com-私var zero = 0; alert(zero); zero = "0"; alert(zero)たちがプリミティブintからプリミティブstringに問題なく移行したというトリックはありません。
JonH '18年

ああ、私はJavaScriptでその "柔軟性" を理解する(しない)のは難しい、新しいことを意味しています。変数の型を変更するために明示的なキャストを必要とする言語に慣れている人のために。ご指摘のとおり、タイプをたとえばプリミティブintからプリミティブに変更するのは非常に簡単stringです。
moey

95

instanceofには、これまでのどのコメントでもカバーされていないように見える重要な側面があります。それは継承です。instanceofを使用して評価される変数は、プロトタイプの継承により、複数の「タイプ」に対してtrueを返す可能性があります。

たとえば、タイプとサブタイプを定義してみましょう:

function Foo(){ //a Foo constructor
    //assign some props
    return this;
}

function SubFoo(){ //a SubFoo constructor
    Foo.call( this ); //inherit static props
    //assign some new props
    return this;
}

SubFoo.prototype = Object.create(Foo.prototype); // Inherit prototype
SubFoo.prototype.constructor = SubFoo;

これで、いくつかの「クラス」ができたので、いくつかのインスタンスを作成して、それらがインスタンスであるものを見つけます。

var 
    foo = new Foo()
,   subfoo = new SubFoo()
;

alert( 
    "Q: Is foo an instance of Foo? "
+   "A: " + ( foo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is foo an instance of SubFoo? " 
+   "A: " + ( foo instanceof SubFoo ) 
); // -> false

alert( 
    "Q: Is subfoo an instance of Foo? "
+   "A: " + ( subfoo instanceof Foo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of SubFoo? "
+   "A: " + ( subfoo instanceof SubFoo ) 
); // -> true

alert( 
    "Q: Is subfoo an instance of Object? "
+   "A: " + ( subfoo instanceof Object ) 
); // -> true

その最後の行を参照してください?関数へのすべての「新しい」呼び出しは、Objectから継承したオブジェクトを返します。これは、オブジェクト作成の省略表現を使用する場合にも当てはまります。

alert( 
    "Q: Is {} an instance of Object? "
+   "A: " + ( {} instanceof Object ) 
); // -> true

そして、「クラス」定義自体はどうですか?それらのインスタンスは何ですか?

alert( 
    "Q: Is Foo an instance of Object? "
+   "A:" + ( Foo instanceof Object) 
); // -> true

alert( 
    "Q: Is Foo an instance of Function? "
+   "A:" + ( Foo instanceof Function) 
); // -> true

オブジェクトをMULTIPLE型のインスタンスにできることを理解することが重要だと思います。なぜなら、私は(誤って)を使用して、たとえばオブジェクトと関数を区別できると想定しているからですinstanceof。この最後の例では、関数オブジェクトであることを明確に示しています。

継承パターンを使用していて、オブジェクトの子孫をダックタイピング以外の方法で確認したい場合にも、これは重要です。

それが探検する人を助けることを願っていますinstanceof


さらに素晴らしいのは、プロトタイプから継承した後SubFoo.prototype = new Foo();、それにメソッドを追加でき、subfoo instanceof Fooチェックも同様に成功することですsubfoo instanceof SubFoo
Cory Danielson

87

ここでの他の答えは正しいですが、instanceof実際にはどのように機能するかについては理解していません。

JavaScriptのすべてのオブジェクトにはプロトタイプがあり、__proto__プロパティからアクセスできます。関数にはprototypeプロパティもあり、これは__proto__それらによって作成されたオブジェクトの初期値です。関数が作成されると、の一意のオブジェクトが与えられますprototypeinstanceofオペレータはあなたに答えを与えるために、この一意性を使用しています。ここでは何instanceofあなたは関数としてそれを書いた場合のように見えるかもしれません。

function instance_of(V, F) {
  var O = F.prototype;
  V = V.__proto__;
  while (true) {
    if (V === null)
      return false;
    if (O === V)
      return true;
    V = V.__proto__;
  }
}

これは基本的に、ECMA-262エディション5.1(ES5とも呼ばれる)のセクション15.3.5.3を言い換えたものです。

任意のオブジェクトを関数のprototypeプロパティに再割り当てでき、オブジェクトの__proto__構築後にオブジェクトのプロパティを再割り当てできることに注意してください。これにより、興味深い結果が得られます。

function F() { }
function G() { }
var p = {};
F.prototype = p;
G.prototype = p;
var f = new F();
var g = new G();

f instanceof F;   // returns true
f instanceof G;   // returns true
g instanceof F;   // returns true
g instanceof G;   // returns true

F.prototype = {};
f instanceof F;   // returns false
g.__proto__ = {};
g instanceof G;   // returns false

5
__proto__IEで" "プロパティを直接操作することは許可されていません。正しく思い出せば、プロパティの直接操作もECMA仕様に含まれていないため、学術的な目的以外での割り当てに使用することはおそらくお勧めできません。
webnesto

@webnesto、それは本当です、プロトは仕様にありません。IEがサポートしていないことは知りませんでした。直接操作とは、JSコードにまったく公開されていないということですか、それとも単に書き込み可能ではないということですか?
ジェイコンロッド

2
古いバージョンでは100%確実ではありません。ここ(stackoverflow.com/questions/8413505/proto-for-ie9-or-ie10)のように聞こえますが、IE9では少なくとも読み取り可能です(変更可能ではありません)。また、ブラウザが完全にドロップしているように聞こえるかもしれません。
webnesto

4
protoプロパティの暗黙の存在を理解することは、ユーザーコードにアクセスできるかどうかに関係なく重要です。+10仕様を引用できるとしたら、これはまさに私が探していたものです。
マイクエドワーズ

3
プロトタイプリンクを取得するには、を使用しますObject.getPrototypeOf(o)。これは、__proto__説明したものと同じですが、ECMAScriptに準拠しています。
froginvasion 2014

45

オブジェクトを宣言するときに、instanceofが「new」キーワードを使用して定義されていることに注意してください。JonHの例では、

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

彼が言及しなかったのはこれです。

var color1 = String("green");
color1 instanceof String; // returns false

"new"を指定すると、Stringコンストラクター関数の終了状態が、単に戻り値に設定されるのではなく、color1 varに実際にコピーされました。これは、新しいキーワードが何をするかをよりよく示していると思います。

function Test(name){
    this.test = function(){
        return 'This will only work through the "new" keyword.';
    }
    return name;
}

var test = new Test('test');
test.test(); // returns 'This will only work through the "new" keyword.'
test // returns the instance object of the Test() function.

var test = Test('test');
test.test(); // throws TypeError: Object #<Test> has no method 'test'
test // returns 'test'

「new」を使用すると、関数内の「this」の値が宣言されたvarに割り当てられますが、それを使用しないと、代わりに戻り値が割り当てられます。


2
newJavaScriptのタイプのいずれかを使用しても意味がありません。そのため、受け入れられた回答は初心者にとってはるかに混乱します。text = String('test')options = {}テストするのinstanceofではなく、typeof代わりにでテストします。
ライアン

3
Date.getTime()//失敗します。はい、新しいことが重要です。
Stephen Belanger、2011

1
コンソールで実行してみてください。getTime()が存在しないため、エラーが発生します。新品を使用する必要があります。
Stephen Belanger

8

また、次のようにエラー処理とデバッグに使用できます。

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}

3
//Vehicle is a function. But by naming conventions
//(first letter is uppercase), it is also an object
//constructor function ("class").
function Vehicle(numWheels) {
    this.numWheels = numWheels;
}

//We can create new instances and check their types.
myRoadster = new Vehicle(4);
alert(myRoadster instanceof Vehicle);

3

それは何ですか?

Javascriptはプロトタイプ言語です。つまり、「継承」にプロトタイプを使用します。instanceofコンストラクタ関数の場合、オペレータは、テストprototypepropertypeが中に存在する__proto__オブジェクトのチェーン。これは、次のことを行うことを意味します(testObjが関数オブジェクトであると想定)。

obj instanceof testObj;
  1. オブジェクトのプロトタイプがコンストラクタのプロトタイプと等しいかどうかを確認します。obj.__proto__ === testObj.prototype >>これがtrue instanceof返される場合true
  2. プロトタイプチェーンを登ります。例:obj.__proto__.__proto__ === testObj.prototype >>これがtrue instanceof返される場合trueます。
  3. オブジェクトの完全なプロトタイプが検査されるまで、手順2を繰り返します。オブジェクトのプロトタイプチェーンのどこにも一致しないtestObj.prototype場合、instanceof演算子はを返しfalseます。

例:

function Person(name) {
  this.name = name;
}
var me = new Person('Willem');

console.log(me instanceof Person); // true
// because:  me.__proto__ === Person.prototype  // evaluates true

console.log(me instanceof Object); // true
// because:  me.__proto__.__proto__ === Object.prototype  // evaluates true

console.log(me instanceof Array);  // false
// because: Array is nowhere on the prototype chain

それはどのような問題を解決しますか?

オブジェクトが特定のプロトタイプから派生しているかどうかを簡単にチェックする問題を解決しました。たとえば、関数がさまざまなプロトタイプを持つことができるオブジェクトを受け取ったとき。次に、プロトタイプチェーンのメソッドを使用する前に、instanceof演算子を、これらのメソッドがオブジェクト上にあるかどうかを確認ます。

例:

function Person1 (name) {
  this.name = name;
}

function Person2 (name) {
  this.name = name;
}

Person1.prototype.talkP1 = function () {
  console.log('Person 1 talking');
}

Person2.prototype.talkP2 = function () {
  console.log('Person 2 talking');
}


function talk (person) {
  if (person instanceof Person1) {
    person.talkP1();
  }
  
  if (person instanceof Person2) {
    person.talkP2();
  }
  
  
}

const pers1 = new Person1 ('p1');
const pers2 = new Person2 ('p2');

talk(pers1);
talk(pers2);

ここでは、talk()関数の最初にプロトタイプがオブジェクトに配置されているかどうかがチェックされます。この後、実行する適切なメソッドが選択されます。このチェックを行わないと、存在しないメソッドが実行され、参照エラーが発生する可能性があります。

いつそれが適切でいつ適切でないのですか?

私たちはすでにこれについてちょっと考えました。オブジェクトで何かを行う前に、オブジェクトのプロトタイプをチェックする必要がある場合に使用します。


1
私はあなたが「よりも、他の何かを書きたいと思いますコンストラクタ関数のプロトタイプは、コンストラクタのprototypeプロパティのどこかに表示されます
Bergi

関数が簡単に実行できるPersonX.prototype.talkように、インターフェイスを共有して両方のメソッドに名前を付ける方が適切であることをお伝えしておきtalkますperson.talk()
ベルギ2018

あなたはそれを完全に正しく更新したので、定義はより良いです。指摘してくれてありがとう!
Willem van der Veen 2018

また、__proto__ドキュメントでは使用しないでください。非推奨です- Object.getPrototype()代わりに記述してください
Bergi

1

「いつそれが適切でいつ適切でないか」という質問で、私の2セントは:

instanceofプロダクションコードではめったに役立ちませんが、コードが正しい型のオブジェクトを返す/作成することをアサートしたいテストでは役立ちます。コードが返す/作成するオブジェクトの種類を明確にすることにより、コードを理解して文書化するためのツールとして、テストがより強力になります。


1

instanceofは単に構文上の砂糖ですisPrototypeOf

function Ctor() {}
var o = new Ctor();

o instanceof Ctor; // true
Ctor.prototype.isPrototypeOf(o); // true

o instanceof Ctor === Ctor.prototype.isPrototypeOf(o); // equivalent

instanceof オブジェクトのコンストラクタのプロトタイプに依存するだけです。

コンストラクタは単なる通常の関数です。すべてがJavaScriptのオブジェクトであるため、厳密に言うと、これは関数オブジェクトです。また、すべての関数にはプロトタイプがあるため、この関数オブジェクトにはプロトタイプがあります。

プロトタイプは、通常のオブジェクトであり、別のオブジェクトのプロトタイプチェーン内にあります。つまり、別のオブジェクトのプロトタイプチェーンにいると、オブジェクトがプロトタイプになります。

function f() {} //  ordinary function
var o = {}, // ordinary object
 p;

f.prototype = o; // oops, o is a prototype now
p = new f(); // oops, f is a constructor now

o.isPrototypeOf(p); // true
p instanceof f; // true

このinstanceof演算子は、JavaScriptには存在しないクラスを偽装しているため、使用しないでください。classES2015にもないキーワードにも関わらず、これclassもまた、単なる構文上の糖衣です...しかし、それはまた別の話です。


1
最初の行が間違っています!詳細については、こちらを参照してください。「isPrototypeOf()は、instanceof演算子とは異なります。式「object instanceof AFunction」では、オブジェクトプロトタイプチェーンは、AFunction自体ではなく、AFunction.prototypeに対してチェックされます。」
Yan Foto

1
@ヤンそして、まだinstanceofから派生していisPrototypeOfます。私はこれを構文糖と呼びます。そして、あなたのMDNソースは冗談ですよね?

いいえ、それは冗談ではありませんし、そうではありませんでしたが、それでも間違ったリンクです。私が持っていることを意図してこの1つが投稿しました。技術的なことは知りたくありinstanceof ませんが、と同じことはしませんisPrototypeOf。それでおしまい。
Yan Foto

0

私は実際のアプリケーションを見つけたばかりで、今ではもっと頻繁に使用すると思います。

jQueryイベントを使用する場合、(イベントなしで)直接呼び出すこともできるより一般的な関数を記述したい場合があります。を使用instanceofして、関数の最初のパラメータがのインスタンスであるかどうかを確認し、jQuery.Event適切に対応できます。

var myFunction = function (el) {                
    if (el instanceof $.Event) 
        // event specific code
    else
        // generic code
};

$('button').click(recalc);    // Will execute event specific code
recalc('myParameter');  // Will execute generic code

私の場合、この関数は、すべて(ボタンのクリックイベントを介して)または特定の要素1つだけを計算する必要がありました。私が使用したコード:

var recalc = function (el) { 
    el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
    // calculate...
};
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.