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