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

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

  • что это?
  • какие проблемы он решает?
  • когда это уместно, а когда нет?

10 ответов


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 может быть номером / строкой / пользовательским типом данных. Ну и что!--5--> проверяет ли он объект, чтобы увидеть, имеет ли он тип, указанный выше, принимая 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's a customer silly!

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


есть важный аспект instanceof, который, похоже, не охватывается ни одним из комментариев до сих пор: наследование. Переменная, оцениваемая с помощью 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 = new Foo(); // Inherit prototype

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

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

видишь последнюю строчку? Все "новые" вызовы функции возвращают объект, который наследуется от объекта. Это справедливо даже при использовании стенографии создания объектов:

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

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

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

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


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

каждый объект в JavaScript имеет прототип, доступный через __proto__ собственность. Функции также имеют prototype свойство, которое является начальным __proto__ для любых объектов, созданных ими. При создании функции ей присваивается уникальный объект для prototype. The instanceof оператор использует эту уникальность, чтобы дать вам ответ. Вот что!--2--> может выглядеть, если вы написали его как функцию.

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 edition 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

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

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


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

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

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

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

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


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

The instanceof оператор следует избегать, потому что он подделывает классы, которые не существуют в Javascript. Несмотря на class ключевое слово не в ES2015 либо, так как class снова просто синтаксический сахар для...но это уже другая история.


что это?

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

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

что проблемы это решает?

он решил проблему удобной проверки того, является ли объект производным от определенного прототипа. Например, когда функция получает объект, который может иметь различные прототипы. Затем, перед использованием методов из цепочки прототипов, мы можем использовать instanceof оператор, чтобы проверить, находятся ли эти методы на объекте.

пример:

function Person1 (name) {
  this.name = name;
}

function Person2 (name) {
  this.name = name;
}

Person1.prototype.talkP1 = function () {
  console.log('Person 1 talking');
}

Person2.prototype.talkP2 = function () {
  console.log('Person 2 talking');
}


function talk (person) {
  if (person instanceof Person1) {
    person.talkP1();
  }
  
  if (person instanceof Person2) {
    person.talkP2();
  }
  
  
}

const pers1 = new Person1 ('p1');
const pers2 = new Person2 ('p2');

talk(pers1);
talk(pers2);

здесь


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

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

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

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