web-dev-qa-db-ja.com

JavascriptのisPrototypeOfとinstanceofの違いは何ですか?

私自身の古いコードのいくつかでは、次のものを使用しています。

_Object.prototype.instanceOf = function( iface )
{
 return iface.prototype.isPrototypeOf( this );
};
_

それから私は(例えば)

_[].instanceOf( Array )
_

これは機能しますが、次のように同じように機能します。

_[] instanceof Array
_

さて、確かにこれは非常に単純な例にすぎません。したがって、私の質問は次のとおりです。

_a instanceof b_ [〜#〜] always [〜#〜]b.prototype.isPrototypeOf(a)と同じですか?

46
Steffen Heil

はい、どちらも同じことを行います。どちらもプロトタイプチェーンをトラバースして、その中の特定のオブジェクトを探します。

両方の違いは、それらが何であるか、およびそれらをどのように使用するかです。 isPrototypeOf_Object.prototype_オブジェクトで使用可能な関数であり、次のことをテストできます。 特定のオブジェクトは別のプロトタイプチェーンにあります。このメソッドは_Object.prototype_で定義されているため、すべてのオブジェクトで使用できます。

instanceof演算子であり、オブジェクトと コンストラクター関数)の2つのオペランドが必要です。 、渡された関数prototypeプロパティがオブジェクトのチェーンに存在するかどうかをテストします( [[HasInstance]](V) 内部操作を介して、関数オブジェクトでのみ使用可能)。

例えば:

_function A () {
  this.a = 1;
}
function B () {
  this.b = 2;
}
B.prototype = new A();
B.prototype.constructor = B;

function C () {
  this.c = 3;
}
C.prototype = new B();
C.prototype.constructor = C;

var c = new C();

// instanceof expects a constructor function

c instanceof A; // true
c instanceof B; // true
c instanceof C; // true

// isPrototypeOf, can be used on any object
A.prototype.isPrototypeOf(c); // true
B.prototype.isPrototypeOf(c); // true
C.prototype.isPrototypeOf(c); // true
_
27
CMS

a instanceof bは常にb.prototype.isPrototypeOf(a)と同じですか?

いいえ、a instanceof bは常にb.prototype.isPrototypeOf(a)と同じように動作するとは限りません。

CMSの回答それらが何であるかが異なることを指摘しました(1つは演算子で、もう1つはObject.prototypeオブジェクトで使用可能な組み込みメソッドです)。これは正しいですが、a instanceof bTypeErrorになり、b.prototype.isPrototypeOf(a)が正常に機能する、またはその逆の特殊なケースもあります。

違い#1

instanceofの右側は、コンストラクター関数であることが期待されています。

bが関数でない場合:

  • a instanceof bTypeErrorになります。

  • b.prototype.isPrototypeOf(a)は問題なく動作します。

const b = {
    prototype: {}
};
const a = Object.create( b.prototype );

console.log( b.prototype.isPrototypeOf(a) );    // true
console.log( a instanceof b );                  // TypeError: Right-hand side of 'instanceof' is not callable

違い#2

b.prototype.isPrototypeOf(a)を使用する場合、b.prototypeObject.prototypeから継承する必要があります。

b.prototypeObject.prototype.isPrototypeOf()メソッドにアクセスできない場合:

  • b.prototype.isPrototypeOf(a)TypeErrorになります。
  • a instanceof bは問題なく動作します。
function B() {};
B.prototype = Object.create( null );

const a = new B();

console.log( a instanceof B );              // true
console.log( B.prototype.isPrototypeOf(a) ) // TypeError: B.prototype.isPrototypeOf is not a function

違い#3

instanceofの右側がバインドされた関数である場合、それはそのターゲット関数と同等に扱われます。

Bがバインドされた関数の場合:

  • a instanceof bは問題なく動作します。
  • b.prototype.isPrototypeOf(a)TypeErrorになります(バインドされた関数にはprototypeプロパティがありません)。
function B() {};
const BoundB = B.bind( null );
const a = new B();

console.log( a instanceof BoundB );              // true
console.log( BoundB.prototype.isPrototypeOf(a) ) // TypeError: Cannot read property 'isPrototypeOf' of undefined

結論

  • コンストラクターを使用せずにObject.create()を介して確立されたプロトタイプの継承を処理している場合は、おそらくObject.prototype.isPrototypeOf()メソッドを使用する必要があります(実際、instanceofのユースケースはinstanceofは、右側のパラメーターがコンストラクター関数であることを期待しているという点で、より制限されています)。
  • コンストラクターを扱っている場合は、instanceof演算子を使用することで少し安全になります(バインドされた関数と、Object.prototypeConstructor.prototypeのプロトタイプチェーンにない場合をカバーできます)。
2
Oliver Sieweke

1つは式であり、もう1つはメソッド呼び出しであるため、演算子の優先順位と真実性は異なります。強調すべきことの1つは、両方 プロトタイプチェーンをトラバースする、したがって、一致するプロトタイプと問題のオブジェクトの間に1対1のマッピングがあると想定することはできません。

var i = 0;

function foo()
{
console.log("foo");
console.log(i++ + ": " + Object.prototype.isPrototypeOf(Object) ) //true
console.log(i++ + ": " + Function.prototype.isPrototypeOf(Function) ) //true

console.log(i++ + ": " + Function.prototype.isPrototypeOf(Function) ) //true
console.log(i++ + ": " + Function.prototype.isPrototypeOf(Object) ) //true

console.log(i++ + ": " + RegExp.prototype.isPrototypeOf( RegExp(/foo/) ) ) //true
console.log(i++ + ": " + Object.prototype.isPrototypeOf( RegExp(/foo/) ) ) //true
console.log(i++ + ": " + Function.prototype.isPrototypeOf( RegExp(/foo/) ) ) //false
console.log(i++ + ": " + Object.prototype.isPrototypeOf(Math) ) //true
console.log(i++ + ": " + Math.isPrototypeOf(Math) ) //false
}

function bar()
{
console.log("bar");
console.log(i++ + ": " + (Object instanceof Object) ) //true

console.log(i++ + ": " + (Function instanceof Function) ) //true
console.log(i++ + ": " + (Function instanceof Object) ) //true

console.log(i++ + ": " + (RegExp(/foo/) instanceof RegExp) ) //true
console.log(i++ + ": " + (RegExp(/foo/) instanceof Object)  ) //true
console.log(i++ + ": " + (RegExp(/foo/) instanceof Function) ) //false
console.log(i++ + ": " + (Math instanceof Object) ) //true
console.log(i++ + ": " + (Math instanceof Math) ) //error
}
try
  {
  foo()
  }
catch(e)
  {
  console.log(JSON.stringify(e));
  }
finally
  {
  try
    {
    bar();
    }
  catch(e)
    {
    console.log(JSON.stringify(e));
    }
  }

参照

1
Paul Sweatte