В чем разница между isPrototypeOf и instanceof в Javascript?

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

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

Затем я делаю (например)

[].instanceOf( Array )

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

[] instanceof Array

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

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


person Steffen Heil    schedule 17.03.2010    source источник
comment
Хотя вы всегда можете использовать instanceof (с конструкторами справа), не все объекты могут наследоваться от Object.prototype. Object.create(null) instanceof Something и ({}).instanceOf({prototype:Something.prototype}) сработают (и дадут false) там, где обратное не сработает.   -  person Bergi    schedule 20.11.2013


Ответы (3)


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

Разница между ними заключается в том, что они из себя представляют и как вы их используете, например. 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
person Christian C. Salvadó    schedule 17.03.2010
comment
Итак, единственная разница в том, что я могу использовать isPrototypeOf, если у меня есть только прототип, тогда как мне нужен конструктор для instanceof? (Делает ли моя функция действительно идентичной instanceof?) - person Steffen Heil; 19.03.2010
comment
Ваш текстовый ответ полезен, ваш пример кода меньше. (Он показывает только равные аспекты, но не различия.) Однако у меня возникает другой вопрос: для чего предназначен .constructor? Я видел такой код в некоторых местах, но никогда не писал его сам, и, кажется, он мне не нужен. (Обычно у меня было что-то вроде C.prototype.clazz = C; жесткого.) Почему люди устанавливают конструктор? - person Steffen Heil; 19.03.2010
comment
@Steffen Heil: код, написанный CMS, я думаю, достаточно ясен, он использует самый простой и известный (хотя и не самый эффективный) способ наследования в JavaScript между конструкторами. Попробуйте удалить строку B.prototype.constructor = B и проверьте конструктор экземпляра B: alert((new B).constructor), и вы увидите конструктор функции A. Делая это, он убеждает себя найти в качестве конструктора всех экземпляров B только B. - person yodabar; 20.07.2012
comment
@CMS Можете ли вы также сказать, что instanceof в основном предназначен для псевдоклассического наследования, поскольку он опирается на B.prototype и B, который является конструктором. Ну и что, если B.prototype и B не используются, то есть нет конструктора, когда программа на JavaScript написана строго по прототипному наследованию? В этом случае можно использовать animal.isPrototypeOf(woofie) - person nonopolarity; 08.02.2013
comment
AFAIK instanceof не работает, если не используется функция конструктора, например. Object.create. Похоже, есть и другие проблемы: tobyho.com/ 28.01.2011/проверка типов-в-javascript - person rmoestl; 06.06.2016
comment
Some interesting extra info about speed of both functions: lh5.googleusercontent.com/ For more info: v8project.blogspot.fr/2017/08/v8-release- 61.html?m=1 - person godot; 11.08.2017

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

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

В ответе CMS указано, что они различаются чем они являются (один из них является оператором, а другой other — это встроенный метод, доступный для объекта 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

Отличие №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.prototype не лежит в цепочке прототипов Constructor.prototype).
person Oliver Sieweke    schedule 04.01.2019
comment
Обратите внимание, что проблему, обнаруженную в Разнице #2, также можно избежать, используя Object.prototype.isPrototypeOf.call(B.prototype, a). - person Oliver Sieweke; 04.01.2019
comment
см. квора .com/ - person Pacerier; 28.05.2019

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

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

Ссылки

person Paul Sweatte    schedule 19.11.2013