Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff 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` در واقع نوع را تعریف می‌کند نه تابع تابع سازنده را.
4 changes: 2 additions & 2 deletions 1-js/09-classes/06-instanceof/1-strange-instanceof/task.md
Original file line number Diff line number Diff 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
134 changes: 67 additions & 67 deletions 1-js/09-classes/06-instanceof/article.md
Original file line number Diff line number Diff 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.
چنین بررسی‌ای ممکن است در موارد بسیاری ضروری باشد. برای مثال، می‌توانیم برای ساخت یک تابع *چندریخت (polymorphic)* از آن استفاده کنیم، تابعی که بر اساس نوع آرگومان‌ها با آن‌ها به صورت متفاوت رفتار می‌کند.

## 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.
اگر `obj` به `Class` یا کلاسی که از آن ارث‌بری می‌کند تعلق داشته باشد، این عملگر مقدار `true` را برمی‌گرداند.

For instance:
برای مثال:

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

// is it an object of Rabbit 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 راه‌اندازی بررسی کردن
// فرض کند (animal) را یک جانور 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.instanceof` را ندارند. در این صورت، منطق استاندارد استفاده می‌شود: `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 is true, return true
// otherwise, if we reached the end of the chain, return false
// را برگردان true ،است 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) وجود دارد که اگر `objA` جایی در زنجیره پروتوتایپ `objB` وجود داشته باشد `true` را برمی‌گرداند. پس بررسی `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.toString for 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` درون‌ساخت می‌تواند از شیء استخراج شود و در زمینه (context) هر مقدار دیگری اجرا شود. و نتیجه‌اش به آن مقدار بستگی دارد.

- 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
// copy toString method 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 @@ -172,11 +172,11 @@ alert( s.call(null) ); // [object Null]
alert( s.call(alert) ); // [object Function]
```

### Symbol.toStringTag
### متد 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
// toStringTag for 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 "typeof on steroids" that not only works for primitive data types, but also for built-in objects and even can be customized.
در نهایت ما «انواعی از استروئیدها» را داریم که نه تنها برای انواع داده اصلی کار می‌کند، بلکه برای شیءهای درون‌ساخت هم کار می‌کند و حتی می‌تواند شخصی‌سازی شود.

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.
زمانی که می‌خواهیم نوع داده را به عنوان یک رشته دریافت کنیم تا اینکه فقط بررسی کنیم، می‌توانیم به جای `instanceof` از `{}.toString.call` برای شیءهای درون‌ساخت استفاده کنیم.

## 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` واقعا می‌درخشد.