web-dev-qa-db-ja.com

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

JavaScriptはオブジェクト指向プログラミング言語ではないと人々が考える傾向があるので、JavaScriptのinstanceofキーワードは最初に出くわしたときにはかなり混乱を招く可能性があります。

  • それは何ですか?
  • それはどんな問題を解決しますか?
  • それが適切な場合とそうでない場合
294
Alon Gubkin

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

pp instanceof Personを継承するため、Person.prototypeはtrueです。

OPのリクエストごと

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

変数を宣言するとき、特定の型を与えます。

例えば:

int i;
float f;
Customer c;

上記はいくつかの変数、すなわちif、およびcを示しています。タイプは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!

上記で、cCustomer型で宣言されていることがわかりました。それを新規作成し、タイプがCustomerかどうかを確認しました。確かに、trueを返します。その後、まだCustomerオブジェクトを使用して、それがStringかどうかを確認します。いいえ、間違いなくStringではなく、CustomerオブジェクトではなくStringオブジェクトを新しくしました。この場合、falseを返します。

本当に簡単です!

260
JonH

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 = new Foo(); // Inherit prototype

これで、いくつかの「クラス」が作成されたので、いくつかのインスタンスを作成し、それらが何のインスタンスであるかを調べます。

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

最後の行を見ますか?関数へのすべての "new"呼び出しは、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

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

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

誰もがinstanceofを探索するのに役立つことを願っています。

91
webnesto

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

JavaScriptのすべてのオブジェクトはプロトタイプを持ち、__proto__プロパティを通してアクセス可能です。関数にはprototypeプロパティもあります。これは、それらによって作成されたオブジェクトの最初の__proto__です。関数が作成されるとき、それはprototypeのためのユニークなオブジェクトを与えられます。 instanceof演算子は、この一意性を使って答えを得ます。これを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
86
Jay Conrod

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に割り当てられますが、使用しない場合は代わりに戻り値が割り当てられます。

45

そして、これをエラー処理やデバッグに使うことができます。

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}
8
Tarek Saied
//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
yfeldblum

それは何ですか?

Javascriptはプロトタイプ言語であり、「継承」にプロトタイプを使用することを意味します。 instanceof演算子は、コンストラクタ関数のprototypeプロパティ型がオブジェクトの__proto__チェーンに存在するかどうかをテストします。これは次のことを行うことを意味します(testObjが関数オブジェクトであると仮定して)。

obj instanceof testObj;
  1. オブジェクトのプロトタイプがコンストラクタのプロトタイプと等しいかどうかを確認します。obj.__proto__ === testObj.prototype >>これがtrueである場合instanceoftrueを返します。
  2. プロトタイプチェーンを登ります。例:obj.__proto__.__proto__ === testObj.prototype >>これがtrueの場合instanceoftrueを返します。
  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()関数で、プロトタイプがオブジェクト上にあるかどうかを最初にチェックします。その後、適切なメソッドが選択されて実行されます。このチェックを行わないと、存在しないメソッドが実行され、参照エラーが発生する可能性があります。

それが適切な場合とそうでない場合

私たちはすでにこれを乗り越えたようなものです。あなたがそれで何かをする前にあなたがオブジェクトのプロトタイプをチェックする必要があるときそれを使ってください。

2

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

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

1
Andrew Magee

instanceofisPrototypeOfの単なる構文上の糖です。

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には存在しないクラスを偽造するため、避けるべきです。 classキーワードもES2015にはありませんが、classは単なる構文上の糖であるためです。

1
user6445533

実社会のアプリケーションを見つけたので、今度はもっと頻繁に使用するようになると思います。

あなたが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...
};
0
jussty