Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Class checking: "instanceof"#227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
tarasyyyk merged 1 commit intojavascript-tutorial:masterfromdolgachio:master
Dec 6, 2021
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
Yeah, looks strange indeed.
Так, виглядає справді дивно.

But `instanceof`does not care about the function, but rather about its`prototype`,that it matches against the prototype chain.
Але `instanceof`нема діла до функції, все залежить від її властивості`prototype`,значення якої порівнюється з ланцюжком прототипів.

And here `a.__proto__ == B.prototype`,so `instanceof`returns `true`.
І тут `a.__proto__ == B.prototype`,тому `instanceof`повертає `true`.

So, by the logic of`instanceof`,the `prototype`actually defines the type, not the constructor function.
Отже, за логікою`instanceof`,властивість `prototype`насправді визначає тип, а не сама функція-конструктор.
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -2,9 +2,9 @@ importance: 5

---

#Strange instanceof
#Дивний instanceof

In the code below, why does`instanceof`return `true`? We can easily see that `a`is not created by `B()`.
Чому`instanceof`повертає `true` у коді нижче? Ми можемо легко побачити, що `a`не створюється `B()`.

```js run
function A() {}
Expand Down
132 changes: 66 additions & 66 deletions1-js/09-classes/06-instanceof/article.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,62 @@
#Class checking: "instanceof"
#Перевірка класу: "instanceof"

The `instanceof`operator allows to check whether an object belongs to a certain class. It also takes inheritance into account.
Оператор `instanceof`дозволяє перевірити, чи належить об’єкт до певного класу. Він також враховує наслідування.

Such a check may be necessary in many cases. For example, it can be used for building a *polymorphic* function, the one that treats arguments differently depending on their type.
Така перевірка може знадобитися в багатьох випадках. Наприклад, його можна використати для створення *поліморфної* функції, яка обробляє аргументи по-різному залежно від їх типу.

##The instanceof operator [#ref-instanceof]
##Оператор instanceof [#ref-instanceof]

The syntax is:
Синтаксис такий:
```js
obj instanceof Class
```

It returns `true` if `obj`belongs to the `Class`or a class inheriting from it.
Він повертає `true`, якщо `obj`належить до класу `Class`або класу, який наслідується від нього.

For instance:
Наприклад:

```js run
class Rabbit {}
let rabbit = new Rabbit();

//is it an object ofRabbit class?
//Чи це об’єкт класуRabbit?
*!*
alert( rabbit instanceof Rabbit ); // true
*/!*
```

It also works with constructor functions:
Він також працює з функціями-конструкторами:

```js run
*!*
//instead of class
//замість класу
function Rabbit() {}
*/!*

alert( new Rabbit() instanceof Rabbit ); // true
```

...And with built-in classes like `Array`:
...І з вбудованими класами як `Array`:

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

Please note that`arr`also belongs to the `Object` class. That's because`Array`prototypically inherits from `Object`.
Будь ласка, зверніть увагу, що`arr`також належить до класу `Object`. Це тому, що клас`Array`прототипно наслідується від `Object`.

Normally, `instanceof`examines the prototype chain for the check. We can also set a custom logic in the static method`Symbol.hasInstance`.
Зазвичай, `instanceof`перевіряє ланцюжок прототипів. Ми також можемо задати будь-яку спеціальну логіку в статичному методі`Symbol.hasInstance`, і замінити звичайну поведінку.

The algorithm of`obj instanceof Class`works roughly as follows:
Алгоритм операції`obj instanceof Class`працює приблизно наступним чином:

1.If there's a static method`Symbol.hasInstance`,then just call it: `Class[Symbol.hasInstance](obj)`.It should return either`true`or `false`,and we're done. That's how we can customize the behavior of `instanceof`.
1.Якщо є статичний метод`Symbol.hasInstance`,тоді він просто викликаєтсья: `Class[Symbol.hasInstance](obj)`.Він повинен повернути`true`або `false`,ось і все. Ось як ми можемо задати поведінку `instanceof`.

For example:
Наприклад:

```js run
//setup instanceOf check that assumes that
//anything with canEat property is an animal
//задамо перевірку instanceof таким чином,
//що будь-що із властивістю canEat - це тварина
class Animal {
static [Symbol.hasInstance](obj) {
if (obj.canEat) return true;
Expand All@@ -65,24 +65,24 @@ The algorithm of `obj instanceof Class` works roughly as follows:

let obj = { canEat: true };

alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj)is called
alert(obj instanceof Animal); // true: Animal[Symbol.hasInstance](obj)було викликано
```

2.Most classes do not have`Symbol.hasInstance`.In that case, the standard logic is used: `obj instanceOf Class`checks whether `Class.prototype`is equal to one of the prototypes in the`obj` prototype chain.
2.Більшість класів не мають`Symbol.hasInstance`.У цьому випадку використовується стандартна логіка: `obj instanceOf Class`перевіряє чи `Class.prototype`дорівнює одному з прототипів у ланцюжку прототипів`obj`.

In other words, compare one after another:
Іншими словами, прототипи порівнюються один за одним:
```js
obj.__proto__ === Class.prototype?
obj.__proto__.__proto__ === Class.prototype?
obj.__proto__.__proto__.__proto__ === Class.prototype?
...
//if any answer istrue,returntrue
//otherwise, if we reached the end of the chain, return false
//Якщо будь-яке з них будеtrue,то instanceof одразу ж вернеtrue.
//Якщо ми досягли кінця ланцюжка - повертається false
```

In the example above `rabbit.__proto__ === Rabbit.prototype`,so that gives the answer immediately.
У наведеному вище прикладі `rabbit.__proto__ === Rabbit.prototype`,тому ми знаходимо відповідь негайно.

In the case of an inheritance, the match will be at the second step:
У разі наслідування ми знайдемо те, що шукали, на другому кроці:

```js run
class Animal {}
Expand All@@ -93,76 +93,76 @@ The algorithm of `obj instanceof Class` works roughly as follows:
alert(rabbit instanceof Animal); // true
*/!*

// rabbit.__proto__ === Animal.prototype (no match)
// rabbit.__proto__ === Animal.prototype (немає збігу)
*!*
// rabbit.__proto__.__proto__ === Animal.prototype (match!)
// rabbit.__proto__.__proto__ === Animal.prototype (знайшли!)
*/!*
```

Here's the illustration of what `rabbit instanceof Animal`compares with`Animal.prototype`:
Ось ілюстрація того, як операція `rabbit instanceof Animal`шукає`Animal.prototype` у прототипах:

![](instanceof.svg)

By the way, there's also a method[objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf),that returns `true`if `objA`is somewhere in the chain of prototypes for`objB`.So the test of`obj instanceof Class`can be rephrased as `Class.prototype.isPrototypeOf(obj)`.
До речі, є також метод[objA.isPrototypeOf(objB)](mdn:js/object/isPrototypeOf),який повертає `true`якщо `objA`знаходиться десь у ланцюжку прототипів для`objB`.Отже, перевірку`obj instanceof Class`можна замінити на `Class.prototype.isPrototypeOf(obj)`.

It's funny, but the`Class`constructor itself does not participate in the check! Only the chain of prototypes and `Class.prototype` matters.
Цікаво, але сам класс`Class`не бере участі в перевірці! Має значення лише ланцюжок прототипів і `Class.prototype`.

That can lead to interesting consequences when a `prototype`property is changed after the object is created.
Це може призвести до дивних наслідків, коли властивість `prototype`було змінено після створення об’єкта.

Like here:
Як тут:

```js run
function Rabbit() {}
let rabbit = new Rabbit();

//changed the prototype
//Змінюємо прототип
Rabbit.prototype = {};

// ...not a rabbit any more!
// ...це більше не rabbit!
*!*
alert( rabbit instanceof Rabbit ); // false
*/!*
```

##Bonus: Object.prototype.toStringfor the type
##Бонус: Object.prototype.toStringдля визначення типу

We already know that plain objects are converted to string as `[object Object]`:
Ми вже знаємо, що прості об’єкти перетворюються на рядки як `[object Object]`:

```js run
let obj = {};

alert(obj); // [object Object]
alert(obj.toString()); //the same
alert(obj.toString()); //теж саме
```

That's their implementation of `toString`.But there's a hidden feature that makes `toString`actually much more powerful than that. We can use it as an extended`typeof`and an alternative for `instanceof`.
Це їх реалізація метода `toString`.Але є прихована функція, яка робить метод `toString`набагато потужнішим. Ми можемо використовувати його як розширений`typeof`і альтернативу `instanceof`.

Sounds strange? Indeed. Let's demystify.
Звучить дивно? Дійсно. Давайте розбиратися.

By [specification](https://tc39.github.io/ecma262/#sec-object.prototype.tostring),the built-in `toString`can be extracted from the object and executed in the context of any other value. And its result depends on that value.
У [специфікації](https://tc39.github.io/ecma262/#sec-object.prototype.tostring),вбудований метод `toString`можна витягнути з об’єкта та викликати в контексті будь-якого іншого значення. І результат залежить від типу цього значення.

-For a number, it will be `[object Number]`
-For a boolean, it will be `[object Boolean]`
-For `null`: `[object Null]`
-For `undefined`: `[object Undefined]`
-For arrays: `[object Array]`
- ...etc (customizable).
-Для числа це буде `[object Number]`
-Для логічного значення це буде `[object Boolean]`
-Для `null`: `[object Null]`
-Для `undefined`: `[object Undefined]`
-Для масивів: `[object Array]`
- ...тощо.

Let's demonstrate:
Давайте продемонструємо:

```js run
//copytoStringmethod into a variable for convenience
//скопіюємо методtoStringу змінну для зручності
let objectToString = Object.prototype.toString;

//what type is this?
//Що це за тип?
let arr = [];

alert( objectToString.call(arr) ); // [object *!*Array*/!*]
```

Here we used [call](mdn:js/function/call) as described in the chapter[](info:call-apply-decorators) to execute the function`objectToString`in the context `this=arr`.
Тут ми використали [call](mdn:js/function/call), як описано в розділі[](info:call-apply-decorators), щоб викликати функцію`objectToString`з контекстом `this=arr`.

Internally, the `toString`algorithm examines`this`and returns the corresponding result. More examples:
Всередені алгоритм `toString`перевіряє`this`і повертає відповідний результат. Більше прикладів:

```js run
let s = Object.prototype.toString;
Expand All@@ -174,9 +174,9 @@ alert( s.call(alert) ); // [object Function]

### Symbol.toStringTag

The behavior of Object`toString`can be customized using a special object property `Symbol.toStringTag`.
Поведінку методу об’єкта`toString`можна налаштувати за допомогою спеціальної властивості `Symbol.toStringTag`.

For instance:
Наприклад:

```js run
let user = {
Expand All@@ -186,33 +186,33 @@ let user = {
alert( {}.toString.call(user) ); // [object User]
```

For most environment-specific objects, there is such a property. Here are some browser specific examples:
Для більшості специфічних для середовища об’єктів така властивість є. Ось деякі приклади для браузера:

```js run
// toStringTagfor the environment-specific object and class:
// 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]
```

As you can see, the result is exactly`Symbol.toStringTag` (if exists),wrapped into `[object ...]`.
Як бачите, результатом є саме`Symbol.toStringTag` (якщо існує),загорнутий у `[object ...]`.

At the end we have"typeofon steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
Наприкінці ми маємо"typeofна стероїдах", який працює не тільки для примітивних типів даних, але й для вбудованих об’єктів і навіть може бути кастомізований.

We can use `{}.toString.call`instead of`instanceof`for built-in objects when we want to get the type as a string rather than just to check.
Ми можемо використати `{}.toString.call`замість`instanceof`для вбудованих об’єктів, коли ми хочемо отримати тип у вигляді рядка, а не просто для перевірки.

##Summary
##Підсумки

Let's summarize the type-checking methods that we know:
Давайте підсумуємо відомі нам методи перевірки типів:

| |works for |returns |
| |працює для |повертає |
|---------------|-------------|---------------|
| `typeof` |primitives |string |
| `{}.toString` |primitives, built-in objects, objects with `Symbol.toStringTag` |string |
| `instanceof` |objects | true/false |
| `typeof` |примітивів |рядок |
| `{}.toString` |примітивів, вбудованих об’єктів, об’єктів з `Symbol.toStringTag` |рядок |
| `instanceof` |об’єктів | true/false |

As we can see, `{}.toString`is technically a "more advanced" `typeof`.
Як ми бачимо, `{}.toString`технічно є "більш просунутим" `typeof`.

And`instanceof`operator really shines when we are working with a class hierarchy and want to check for the class taking into account inheritance.
І оператор`instanceof`дійсно сяє, коли ми працюємо з ієрархією класів і хочемо перевірити клас з урахуванням наслідування.

[8]ページ先頭

©2009-2025 Movatter.jp