Какая разница между isPrototypeOf и instanceof в Javascript?
В моем собственном более старом коде я использую следующее:
Object.prototype.instanceOf = function( iface )
{
return iface.prototype.isPrototypeOf( this );
};
Тогда я делаю (например)
[].instanceOf( Array )
Это работает, но, похоже, следующее будет делать то же самое:
[] instanceof Array
Теперь, конечно, это всего лишь очень простой пример. Поэтому мой вопрос:
Является ли a instanceof b
ВСЕГДА так же, как b.prototype.isPrototypeOf(a)
?
Ответы
Ответ 1
Да, они делают то же самое, оба пересекают цепочку прототипов, ища конкретный объект в ней.
Различие между ними - это то, что они есть, и то, как вы их используете, например. 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
Является a instanceof b
ВСЕГДА тем же, что и b.prototype.isPrototypeOf(a)
?
Нет, a instanceof b
не всегда будет вести себя так же, как b.prototype.isPrototypeOf(a)
.
В ответе CMS указывалось, что они отличаются друг от друга (один является оператором, а другой - встроенным методом, доступным для объекта Object.prototype
). Это верно, однако есть и некоторые частные случаи, для которых a instanceof b
приведет к TypeError
во время b.prototype.isPrototypeOf(a)
будет работать нормально, и наоборот.
Разница № 1
Ожидается, что правая часть instanceof
будет функцией конструктора.
Если b
не является функцией:
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
Ответ 3
Приоритет и правдивость операторов различаются, поскольку один является выражением, а другой - вызовом метода. Следует подчеркнуть, что оба пересекают цепочку прототипов, поэтому вы не можете предположить, что между сопоставимым прототипом и рассматриваемым объектом существует взаимно однозначное соответствие:
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));
}
}