Javascript not instanceof object

Проверка класса: «instanceof»

Оператор instanceof позволяет проверить, принадлежит ли объект указанному классу, с учётом наследования.

Такая проверка может потребоваться во многих случаях. Здесь мы используем её для создания полиморфной функции, которая интерпретирует аргументы по-разному в зависимости от их типа.

Оператор instanceof

Оператор вернёт true , если obj принадлежит классу Class или наследующему от него.

class Rabbit <> let rabbit = new Rabbit(); // это объект класса Rabbit? alert( rabbit instanceof Rabbit ); // true

Также это работает с функциями-конструкторами:

// вместо класса function Rabbit() <> alert( new Rabbit() instanceof Rabbit ); // true

…И для встроенных классов, таких как Array :

let arr = [1, 2, 3]; alert( arr instanceof Array ); // true alert( arr instanceof Object ); // true

Пожалуйста, обратите внимание, что arr также принадлежит классу Object , потому что Array наследует от Object .

Обычно оператор instanceof просматривает для проверки цепочку прототипов. Но это поведение может быть изменено при помощи статического метода Symbol.hasInstance .

Алгоритм работы obj instanceof Class работает примерно так:

    Если имеется статический метод Symbol.hasInstance , тогда вызвать его: Class[Symbol.hasInstance](obj) . Он должен вернуть либо true , либо false , и это конец. Это как раз и есть возможность ручной настройки instanceof . Пример:

// проверка instanceof будет полагать, // что всё со свойством canEat - животное Animal class Animal < static [Symbol.hasInstance](obj) < if (obj.canEat) return true; >> let obj = < canEat: true >; alert(obj instanceof Animal); // true: вызван Animal[Symbol.hasInstance](obj)
obj.__proto__ === Class.prototype? obj.__proto__.__proto__ === Class.prototype? obj.__proto__.__proto__.__proto__ === Class.prototype? . // если какой-то из ответов true - возвратить true // если дошли до конца цепочки - false

В примере выше rabbit.__proto__ === Rabbit.prototype , так что результат будет получен немедленно. В случае с наследованием, совпадение будет на втором шаге:

class Animal <> class Rabbit extends Animal <> let rabbit = new Rabbit(); alert(rabbit instanceof Animal); // true // rabbit.__proto__ === Animal.prototype (нет совпадения) // rabbit.__proto__.__proto__ === Animal.prototype (совпадение!)

Вот иллюстрация того как rabbit instanceof Animal сравнивается с Animal.prototype :

Кстати, есть метод objA.isPrototypeOf(objB), который возвращает true , если объект objA есть где-то в прототипной цепочке объекта objB . Так что obj instanceof Class можно перефразировать как Class.prototype.isPrototypeOf(obj) .

Забавно, но сам конструктор Class не участвует в процессе проверки! Важна только цепочка прототипов Class.prototype .

Это может приводить к интересным последствиям при изменении свойства prototype после создания объекта.

function Rabbit() <> let rabbit = new Rabbit(); // заменяем прототип Rabbit.prototype = <>; // . больше не rabbit! alert( rabbit instanceof Rabbit ); // false

Бонус: Object.prototype.toString возвращает тип

Мы уже знаем, что обычные объекты преобразуются к строке как [object Object] :

let obj = <>; alert(obj); // [object Object] alert(obj.toString()); // то же самое

Так работает реализация метода toString . Но у toString имеются скрытые возможности, которые делают метод гораздо более мощным. Мы можем использовать его как расширенную версию typeof и как альтернативу instanceof .

Звучит странно? Так и есть. Давайте развеем мистику.

Согласно спецификации встроенный метод toString может быть позаимствован у объекта и вызван в контексте любого другого значения. И результат зависит от типа этого значения.

  • Для числа это будет [object Number]
  • Для булева типа это будет [object Boolean]
  • Для null : [object Null]
  • Для undefined : [object Undefined]
  • Для массивов: [object Array]
  • …и т.д. (поведение настраивается).
// скопируем метод toString в переменную для удобства let objectToString = Object.prototype.toString; // какой это тип? let arr = []; alert( objectToString.call(arr) ); // [object Array]

В примере мы использовали call, как описано в главе Декораторы и переадресация вызова, call/apply, чтобы выполнить функцию objectToString в контексте this=arr .

Внутри, алгоритм метода toString анализирует контекст вызова this и возвращает соответствующий результат. Больше примеров:

let s = Object.prototype.toString; alert( s.call(123) ); // [object Number] alert( s.call(null) ); // [object Null] alert( s.call(alert) ); // [object Function]

Symbol.toStringTag

Поведение метода объектов toString можно настраивать, используя специальное свойство объекта Symbol.toStringTag .

let user = < [Symbol.toStringTag]: "User" >; alert( <>.toString.call(user) ); // [object User]

Такое свойство есть у большей части объектов, специфичных для определённых окружений. Вот несколько примеров для браузера:

// toStringTag для браузерного объекта и класса alert( window[Symbol.toStringTag]); // window alert( XMLHttpRequest.prototype[Symbol.toStringTag] ); // XMLHttpRequest alert( <>.toString.call(window) ); // [object Window] alert( <>.toString.call(new XMLHttpRequest()) ); // [object XMLHttpRequest]

Как вы можете видеть, результат – это значение Symbol.toStringTag (если он имеется) обёрнутое в [object . ] .

В итоге мы получили «typeof на стероидах», который не только работает с примитивными типами данных, но также и со встроенными объектами, и даже может быть настроен.

Можно использовать <>.toString.call вместо instanceof для встроенных объектов, когда мы хотим получить тип в виде строки, а не просто сделать проверку.

Итого

Давайте обобщим, какие методы для проверки типа мы знаем:

работает для возвращает
typeof примитивов строка
<>.toString примитивов, встроенных объектов, объектов с Symbol.toStringTag строка
instanceof объектов true/false

Как мы можем видеть, технически <>.toString «более продвинут», чем typeof .

А оператор instanceof – отличный выбор, когда мы работаем с иерархией классов и хотим делать проверки с учётом наследования.

Источник

Javascript not instanceof object

Last updated: Dec 28, 2022
Reading time · 4 min

banner

# Table of Contents

If you need to check if an object is NOT an instance of a class, click on the second subheading.

# Check if Object is an instance of Class in JavaScript

Use the instanceof operator to check if an object is an instance of a class.

The instanceof operator will return true if the object is an instance of the class and false otherwise.

Copied!
class Person > const p1 = new Person(); if (p1 instanceof Person) console.log('✅ is instance of Person'); > else console.log('⛔️ is not instance of Person'); > class Animal > console.log(p1 instanceof Animal); // 👉️ false

The instanceof operator returns a boolean value indicating whether the prototype property of the constructor appears in the prototype chain of the object.

The p1 object was created using the Person class, so it is an instance of the class.

Here is an example that uses the instanceof operator to determine which method is available on an object.

Copied!
class Person walk() console.log('person is walking'); > > class Animal run() console.log('animal is running'); > > function example(x) // 👉️ x is type Person or Animal here if (x instanceof Person) // 👇️ x is type Person here x.walk(); > else // 👇️ x is type Animal here x.run(); > > const p1 = new Person(); const a1 = new Animal(); example(p1); // 👉️ "person is walking" example(a1); // 👉️ "animal is running"

The function takes a parameter of type Person or Animal , so before we access a class-specific method, we have to check an instance of which class was passed to the function.

If you access the constructor.name property, you can see that the class name of the p1 object is Person .

Copied!
class Person > const p1 = new Person(); console.log(p1.constructor.name); // 👉️ Person

We accessed the name property on the Object.constructor property.

The Object.constructor property returns a reference to the constructor function, from which the object was created.

The instanceof operator checks for the presence of constructor.prototype in the object’s prototype chain.

Copied!
class Person > const p1 = new Person(); // 👇️ true console.log(Object.getPrototypeOf(p1) === Person.prototype);

# Check if an Object is NOT an instanceof a Class in JavaScript

Alternatively, you can use the logical NOT (!) operator.

The logical NOT (!) operator inverts the value the instanceof operator returns.

Copied!
class Person > class Animal > const p1 = new Person(); if (!(p1 instanceof Animal)) console.log('✅ Object is not instance of Animal'); > else console.log('⛔️ Object is instance of Animal'); >

The instanceof operator returns a boolean value indicating if the prototype property of the constructor appears in the prototype chain of the object.

Notice that we used parentheses around the instanceof check before negating it.

A commonly seen mistake is to omit the parentheses, e.g.:

Copied!
// ❌ Don't do this console.log(!p1 instanceof Animal); // 👉️ false

The code sample inverts the value of the object and converts it to a boolean, so it becomes false .

Copied!
class Person > const p1 = new Person(); console.log(!p1); // 👉️ false

We then check if false is an instance of the Animal class which will always return false .

Copied!
class Person > class Animal > const p1 = new Person(); if (!(p1 instanceof Animal)) console.log('✅ Object is not instance of Animal'); > else console.log('⛔️ Object is instance of Animal'); >

The p1 instanceof Animal expression is first evaluated and returns false if the object is not an instance of the class.

Then the logical NOT (!) operator inverts the value to true and the if block runs.

If the object is an instance of the class, the else block runs.

If you don’t like the parentheses approach, compare the value to the boolean false .

# Check if an Object is NOT an instanceof a Class using boolean comparison

This is a three-step process:

  1. Use the instanceof operator to check if the object is an instance of the class.
  2. Compare the output of the expression to false .
  3. If the instanceof operator returned false , the object is not an instance of the class.
Copied!
class Person > class Animal > const p1 = new Person(); if (p1 instanceof Animal === false) console.log('✅ Object is not instance of Animal'); > else console.log('⛔️ Object is instance of Animal'); >

We first used the instanceof operator to test if the p1 object is an instance of the Animal class.

If the test returns false , then the object is not an instance of the class.

This approach achieves the same goal as using the logical NOT (!) operator with parentheses.

However, it might be a bit more readable because you don’t have to think about the order in which the statements are run.

Here are some more examples of using the logical NOT (!) operator.

Copied!
console.log(!true); // 👉️ false console.log(!false); // 👉️ true console.log(!'str'); // 👉️ false console.log(!''); // 👉️ true console.log(!null); // 👉️ true

The logical NOT (!) operator converts truthy values to false and fasly values to true .

The falsy values in JavaScript are: false , 0 , -0 , «» (empty string), null , undefined , NaN (Not a number).

When used with any other than the aforementioned 6 values, the logical NOT (!) operator returns false .

If you decide to use the logical NOT (!) operator approach, make sure to wrap the instanceof test in parentheses.

Copied!
class Person > class Animal > const p1 = new Person(); if (!(p1 instanceof Animal)) console.log('✅ Object is not instance of Animal'); > else console.log('⛔️ Object is instance of Animal'); >

I wrote a book in which I share everything I know about how to become a better, more efficient programmer.

Источник

Читайте также:  Индекс максимального элемента массива питон
Оцените статью