В чем разница между isPrototypeOf и instanceof в Javascript? - PullRequest
42 голосов
/ 17 марта 2010

В некоторых моих собственных старых кодах я использую следующее:

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

Тогда я делаю (например)

[].instanceOf( Array )

Это работает, но, кажется, следующее будет делать то же самое:

[] instanceof Array

Теперь, конечно, это только очень простой пример. Поэтому мой вопрос:

Является ли a instanceof b ВСЕГДА таким же, как b.prototype.isPrototypeOf(a)?

Ответы [ 3 ]

27 голосов
/ 17 марта 2010

Да, они делают одно и то же, оба просматривают цепочку прототипов, ища в ней определенный объект.

Разница между ними в том, что они , и то, как вы их используете, например. isPrototypeOf - это функция , доступная для объекта Object.prototype, она позволяет проверить, находится ли определенный объект в цепочке прототипов другого, поскольку этот метод определен в Object.prototype, он доступен для всех объектов.

instanceof является оператором и ожидает двух операндов, объекта и функции-конструктора , он проверит, передана ли функция prototype свойство существует в цепочке объекта (через внутреннюю операцию [[HasInstance]](V), доступно только в объектах Function).

Например:

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
2 голосов
/ 04 января 2019

a instanceof b ВСЕГДА совпадает с b.prototype.isPrototypeOf(a)?

Нет, a instanceof b не всегда будет вести себя так же, как b.prototype.isPrototypeOf(a).

Другой ответ указал, что они отличаются от того, чем они являются (один - оператор, а другой - встроенный метод, доступный для объекта Object.prototype). Это верно, однако есть также некоторые особые случаи, для которых a instanceof b приведет к TypeError, в то время как b.prototype.isPrototypeOf(a) будет работать нормально и наоборот.

Разница № 1

Ожидается, что правая часть instanceof будет функцией конструктора.

Если b не является функцией:

  • a instanceof b приведет к TypeError.

  • 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.prototype должно наследоваться от Object.prototype:

Если b.prototype не имеет доступа к методу Object.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

Заключение

  • Если вы имеете дело с наследованием прототипов, установленным через Object.create(), без использования конструкторов, вам, вероятно, следует использовать метод Object.prototype.isPrototypeOf(). (Действительно, варианты использования instanceof более ограничены, поскольку instanceof ожидает, что его правый параметр будет функцией конструктора.)
  • Если вы имеете дело с конструкторами, вам будет немного безопаснее, если использовать оператор instanceof. (Вы сможете охватить случаи, когда Object.prototype не лежит в цепочке прототипов Constructor.prototype)
1 голос
/ 20 ноября 2013

Приоритет оператора и достоверность различаются, так как один является выражением, а другой - вызовом метода. Следует подчеркнуть, что оба пересекают цепочку прототипов , поэтому вы не можете предполагать, что между соответствующим прототипом и рассматриваемым объектом существует взаимно-однозначное соответствие:

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));
    }
  }

Ссылки

...