Что такое оператор instanceof в JavaScript?

Ключевое слово instanceof в JavaScript может быть довольно запутанным, когда оно впервые встречается, поскольку люди склонны думать, что JavaScript не является объектно-ориентированным языком программирования.

  • Что это такое?
  • Какие проблемы он разрешает?
  • Когда это подходит, а когда нет?

Ответ 1

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)

Стоит упомянуть о том, что instanceof оценивает значение true, если объект наследуется от прототипа кластера:

var p = new Person("Jon");
p instanceof Person

Это p instanceof Person истинно, так как p наследуется от Person.prototype.

В запросе OP

Я добавил небольшой пример с некоторым примером кода и объяснением.

Когда вы объявляете переменную, вы указываете ее конкретный тип.

Например:

int i;
float f;
Customer c;

Выше показаны некоторые переменные, а именно i, f и c. Типы integer, float и пользовательский тип данных 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 a customer silly!

Выше мы видели, что c был объявлен с типом Customer. Мы новичок и проверили, имеет ли он тип Customer или нет. Конечно, он возвращает true. Затем, используя объект Customer, мы проверяем, является ли это String. Нет, определенно не String мы ввели объект Customer не объект String. В этом случае он возвращает false.

Это действительно так просто!

Ответ 2

В экземпляре экземпляра есть важный аспект, который пока не рассматривается ни в одном из комментариев: наследование. Переменная, оцениваемая с использованием 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 = Object.create(Foo.prototype); // Inherit prototype
SubFoo.prototype.constructor = SubFoo;

Теперь, когда у нас есть пара "классов", давайте создадим несколько экземпляров и выясним, к чему они относятся:

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

Видите эту последнюю строку? Все "новые" вызовы функции возвращают объект, который наследуется от 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

Я чувствую, что понимание того, что любой объект может быть экземпляром MULTIPLE-типов, важно, поскольку вы, я (ошибочно), допускаете, что вы можете различать, скажем, и объект и функцию, используя instanceof. Как видно из последнего примера, функция является объектом.

Это также важно, если вы используете какие-либо шаблоны наследования и хотите подтвердить потомство объекта с помощью методов, отличных от типизации по типу утки.

Надеюсь, что это поможет любому исследовать instanceof.

Ответ 3

Другие ответы здесь правильные, но они не понимают, как работает 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

Ответ 4

Я думаю, стоит отметить, что 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

Задание "нового" фактически скопирует конечное состояние функции конструктора 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, в то время как не используется, вместо этого присваивает возвращаемое значение.

Ответ 5

И вы можете использовать его для обработки и отладки ошибок, например:

try{
    somefunction();
} 
catch(error){
    if (error instanceof TypeError) {
        // Handle type Error
    } else if (error instanceof ReferenceError) {
        // Handle ReferenceError
    } else {
        // Handle all other error types
    }
}

Ответ 6

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

Ответ 7

  Что это?

Javascript - это язык прототипов, что означает, что он использует прототипы для "наследования". оператор instanceof проверяет, присутствует ли свойство свойства функции конструктора prototype в цепочке __proto__ объекта. Это означает, что он будет делать следующее (при условии, что testObj является функциональным объектом):

obj instanceof testObj;
  1. Проверьте, равен ли прототип объекта прототипу конструктора: obj.__proto__ === testObj.prototype >> если это true, instanceof вернет true.
  2. Поднимемся по прототипу цепи. Например: obj.__proto__.__proto__ === testObj.prototype >> если это true, instanceof вернет true.
  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

Ответ 8

На вопрос "Когда это уместно, а когда нет?", мои 2 цента:

instanceof редко используется в производственном коде, но полезен в тестах, в которых вы хотите утверждать, что ваш код возвращает/создает объекты правильных типов. Являясь явным о типах объектов, возвращаемых/созданных вашим кодом, ваши тесты становятся более мощными как инструмент для понимания и документирования вашего кода.

Ответ 9

instanceof - это просто синтаксический сахар для isPrototypeOf:

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 снова является просто синтаксическим сахаром для... но это другая история.

Ответ 10

Я просто нашел приложение реального мира и буду использовать его чаще всего, я думаю.

Если вы используете события 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

В моем случае функция, необходимая для вычисления чего-либо либо для всех (через событие click на кнопке), либо только для одного конкретного элемента. Код, который я использовал:

var recalc = function (el) { 
    el = (el == undefined || el instanceof $.Event) ? $('span.allItems') : $(el);
    // calculate...
};