Skip to content

F.prototype #171

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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 19, 2021
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,20 +1,20 @@

Answers:
پاسخ‌ها:

1. `true`.

The assignment to `Rabbit.prototype` sets up `[[Prototype]]` for new objects, but it does not affect the existing ones.
انتساب به `Rabbit.prototype` ،`[[Prototype]]` را برای اشیاء جدید تنظیم می‌کند، اما بر موارد موجود تأثیری نمی‌گذارد.

2. `false`.

Objects are assigned by reference. The object from `Rabbit.prototype` is not duplicated, it's still a single object referenced both by `Rabbit.prototype` and by the `[[Prototype]]` of `rabbit`.
اشیاء با مرجع تخصیص داده می‌شوند. شیء `Rabbit.prototype` تکراری نیست، همچنان یک شیء واحد است که هم توسط `Rabbit.prototype` و هم توسط `[[Prototype]]` از `rabbit` ارجاع داده شده است.

So when we change its content through one reference, it is visible through the other one.
بنابراین وقتی محتوای آن را از طریق یک مرجع تغییر می‌دهیم، از طریق مرجع دیگر قابل مشاهده است.

3. `true`.

All `delete` operations are applied directly to the object. Here `delete rabbit.eats` tries to remove `eats` property from `rabbit`, but it doesn't have it. So the operation won't have any effect.
تمام عملیات `delete` مستقیماً روی شیء اعمال می‌شود. در اینجا `delete rabbit.eats` سعی می‌کند ویژگی `eats` را از `rabbit` حذف کند، اما آن را ندارد. بنابراین عملیات هیچ تاثیری نخواهد داشت.

4. `undefined`.

The property `eats` is deleted from the prototype, it doesn't exist any more.
ویژگی `eats` از پروتوتایپ حذف شده است، دیگر وجود ندارد.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ importance: 5

---

# Changing "prototype"
# تغییر "prototype"

In the code below we create `new Rabbit`, and then try to modify its prototype.
در کد زیر `new Rabbit` را ایجاد می‌کنیم و سپس سعی می‌کنیم پروتوتایپ آن را تغییر دهیم.

In the start, we have this code:
در شروع، ما این کد را داریم:

```js run
function Rabbit() {}
Expand All @@ -20,7 +20,7 @@ alert( rabbit.eats ); // true
```


1. We added one more string (emphasized). What will `alert` show now?
1. یک رشته دیگر اضافه کردیم (تاکید شده). اکنون `alert` چه چیزی را نشان می‌دهد؟

```js
function Rabbit() {}
Expand All @@ -37,7 +37,7 @@ alert( rabbit.eats ); // true
alert( rabbit.eats ); // ?
```

2. ...And if the code is like this (replaced one line)?
2. ...و اگر کد به این صورت باشد (یک خط جایگزین شده است)؟

```js
function Rabbit() {}
Expand All @@ -54,7 +54,7 @@ alert( rabbit.eats ); // true
alert( rabbit.eats ); // ?
```

3. And like this (replaced one line)?
3. و مثل این (یک خط جایگزین شده است)؟

```js
function Rabbit() {}
Expand All @@ -71,7 +71,7 @@ alert( rabbit.eats ); // true
alert( rabbit.eats ); // ?
```

4. The last variant:
4. آخرین نوع:

```js
function Rabbit() {}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
We can use such approach if we are sure that `"constructor"` property has the correct value.
اگر مطمئن باشیم که ویژگی `"constructor"` مقدار صحیحی دارد، می‌توانیم از چنین رویکردی استفاده کنیم.

For instance, if we don't touch the default `"prototype"`, then this code works for sure:
برای مثال، اگر `"prototype"` پیش‌فرض را تغییر ندهیم، این کد مطمئناً کار می‌کند:

```js run
function User(name) {
Expand All @@ -10,14 +10,14 @@ function User(name) {
let user = new User('John');
let user2 = new user.constructor('Pete');

alert( user2.name ); // Pete (worked!)
alert( user2.name ); // Pete (کار کرد!)
```

It worked, because `User.prototype.constructor == User`.
کار کرد، زیرا `User.prototype.constructor == User`.

..But if someone, so to speak, overwrites `User.prototype` and forgets to recreate `constructor` to reference `User`, then it would fail.
..اما اگر شخصی، به اصطلاح، `User.prototype` را بازنویسی کند و فراموش کند `constructor` را برای ارجاع به `User` بازآفرینی کند، آنگاه شکست خواهد خورد.

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

```js run
function User(name) {
Expand All @@ -33,17 +33,17 @@ let user2 = new user.constructor('Pete');
alert( user2.name ); // undefined
```

Why `user2.name` is `undefined`?
چرا `user2.name` برابر با `undefined` است؟

Here's how `new user.constructor('Pete')` works:
در اینجا نحوه عملکرد `new user.constructor('Pete')` وجود دارد:

1. First, it looks for `constructor` in `user`. Nothing.
2. Then it follows the prototype chain. The prototype of `user` is `User.prototype`, and it also has no `constructor` (because we "forgot" to set it right!).
3. Going further up the chain, `User.prototype` is a plain object, its prototype is the built-in `Object.prototype`.
4. Finally, for the built-in `Object.prototype`, there's a built-in `Object.prototype.constructor == Object`. So it is used.
1. ابتدا، به دنبال `constructor` در `user` می‌گردد. هیچ‌چیز.
2. سپس از زنجیره پروتوتایپ پیروی می‌کند. پروتوتایپ `user` برابر با `User.prototype` است، و همچنین `constructor` ندارد (زیرا ما «فراموش کردیم» آن را درست تنظیم کنیم!).
3. در ادامه زنجیره، `User.prototype` یک شیء ساده است، پروتوتایپ آن `Object.prototype` داخلی است.
4. در نهایت، برای `Object.prototype` داخلی، `Object.prototype.constructor == Object` داخلی وجود دارد. بنابراین استفاده می‌شود.

Finally, at the end, we have `let user2 = new Object('Pete')`.
سر‌انجام، در پایان، `let user2 = new Object('Pete')` را داریم.

Probably, that's not what we want. We'd like to create `new User`, not `new Object`. That's the outcome of the missing `constructor`.
احتمالاً این چیزی نیست که ما می‌خواهیم. ما می‌خواهیم `new User` ایجاد کنیم، نه `new Object`. این نتیجه `constructor` گم شده است.

(Just in case you're curious, the `new Object(...)` call converts its argument to an object. That's a theoretical thing, in practice no one calls `new Object` with a value, and generally we don't use `new Object` to make objects at all).
(فقط در صورتی که کنجکاو باشید، فراخوانی `new Object(...)` آرگومان خود را به یک شیء تبدیل می‌کند. این یک چیز تئوری است، در عمل هیچ‌کس `new Object` را با مقدار نمی‌نامد، و عموماً ما اصلاً از `new Object` برای ساختن اشیاء استفاده نمی‌کنیم).
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ importance: 5

---

# Create an object with the same constructor
# یک شیء با سازنده یکسان ایجاد کنید

Imagine, we have an arbitrary object `obj`, created by a constructor function -- we don't know which one, but we'd like to create a new object using it.
تصور کنید، یک شیء دلخواه `obj` داریم که توسط یک تابع سازنده ایجاد شده است -- نمی‌دانیم کدام یک، اما می‌خواهیم با استفاده از آن یک شیء جدید ایجاد کنیم.

Can we do it like that?
می‌توانیم آن را انجام دهیم؟

```js
let obj2 = new obj.constructor();
```

Give an example of a constructor function for `obj` which lets such code work right. And an example that makes it work wrong.
مثالی از یک تابع سازنده برای `obj` بیاورید که به این کد اجازه می‌دهد درست کار کند. و مثالی که باعث می‌شود اشتباه کار کند.
98 changes: 49 additions & 49 deletions 1-js/08-prototypes/02-function-prototype/article.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
# F.prototype

Remember, new objects can be created with a constructor function, like `new F()`.
به خاطر داشته باشید، شیء‌های جدید را می‌توان با یک تابع سازنده ایجاد کرد، مثل `new F()`.

If `F.prototype` is an object, then the `new` operator uses it to set `[[Prototype]]` for the new object.
اگر `F.prototype` یک شیء باشد، عملگر `new` از آن برای تنظیم `[[Prototype]]` برای شیء جدید استفاده می‌کند.

```smart
JavaScript had prototypal inheritance from the beginning. It was one of the core features of the language.
جاوا‌اسکریپت از ابتدا دارای وراثت پروتوتایپ بود. این یکی از ویژگی‌های اصلی زبان بود.

But in the old times, there was no direct access to it. The only thing that worked reliably was a `"prototype"` property of the constructor function, described in this chapter. So there are many scripts that still use it.
اما در قدیم، دسترسی مستقیم به آن وجود نداشت. تنها چیزی که به طور قابل اعتماد کار می‌کرد ویژگی `"prototype"` تابع سازنده بود که در این فصل توضیح داده شد. بنابراین اسکریپت‌های زیادی وجود دارند که هنوز از آن استفاده می‌کنند.
```

Please note that `F.prototype` here means a regular property named `"prototype"` on `F`. It sounds something similar to the term "prototype", but here we really mean a regular property with this name.
لطفاً توجه داشته باشید که `F.prototype` در اینجا به معنای یک ویژگی معمولی به نام `"prototype"` در `F` است. چیزی شبیه به اصطلاح "prototype" به نظر می‌رسد، اما در اینجا واقعاً به معنای یک ویژگی معمولی با این نام است.

Here's the example:
در اینجا یک مثال وجود دارد:

```js run
let animal = {
Expand All @@ -27,95 +27,95 @@ function Rabbit(name) {
Rabbit.prototype = animal;
*/!*

let rabbit = new Rabbit("White Rabbit"); // rabbit.__proto__ == animal
let rabbit = new Rabbit("خرگوش سفید"); // rabbit.__proto__ == animal

alert( rabbit.eats ); // true
```

Setting `Rabbit.prototype = animal` literally states the following: "When a `new Rabbit` is created, assign its `[[Prototype]]` to `animal`".
تنظیم `Rabbit.prototype = animal` به معنای واقعی کلمه این موارد را بیان می‌کند: «وقتی یک `new Rabbit` ایجاد شد، `[[Prototype]]` آن را به `animal` اختصاص دهید«.

That's the resulting picture:
این تصویر نتیجه است:

![](proto-constructor-animal-rabbit.svg)

On the picture, `"prototype"` is a horizontal arrow, meaning a regular property, and `[[Prototype]]` is vertical, meaning the inheritance of `rabbit` from `animal`.
در تصویر، `"prototype"` یک فلش افقی است، به معنای یک ویژگی معمولی، و `[[Prototype]]` عمودی است، به معنای ارث بردن `rabbit` از `animal`.

```smart header="`F.prototype` only used at `new F` time"
`F.prototype` property is only used when `new F` is called, it assigns `[[Prototype]]` of the new object.
```smart header="`F.prototype` فقط در زمان `new F` استقاده می‌شود"
ویژگی `F.prototype` تنها زمانی استفاده می‌شود که `new F` فراخوانی شود، `[[Prototype]]` را به شیء جدید اختصاص می‌دهد.

If, after the creation, `F.prototype` property changes (`F.prototype = <another object>`), then new objects created by `new F` will have another object as `[[Prototype]]`, but already existing objects keep the old one.
اگر پس از ایجاد، ویژگی `F.prototype` تغییر کند (`F.prototype = <یک شیء دیگر>`)، آنگاه اشیاء جدید ایجاد شده توسط `new F` شیء دیگری به عنوان `[[Prototype]]` خواهند داشت، اما اشیاء موجود، شیء قدیمی را حفظ می‌کنند.
```

## Default F.prototype, constructor property
## F.prototype پیش‌فرض، ویژگی سازنده

Every function has the `"prototype"` property even if we don't supply it.
هر تابع دارای ویژگی `"prototype"` است، حتی اگر آن را تنظیم نکنیم.

The default `"prototype"` is an object with the only property `constructor` that points back to the function itself.
`"prototype"` پیش‌فرض یک شیء با تنها ویژگی `constructor` است که به خود تابع اشاره می‌کند.

Like this:
مثل این:

```js
function Rabbit() {}

/* default prototype
/* پیش‌فرض prototype
Rabbit.prototype = { constructor: Rabbit };
*/
```

![](function-prototype-constructor.svg)

We can check it:
ما می‌توانیم آن را بررسی کنیم:

```js run
function Rabbit() {}
// by default:
// به صورت پیش‌فرض:
// Rabbit.prototype = { constructor: Rabbit }

alert( Rabbit.prototype.constructor == Rabbit ); // true
```

Naturally, if we do nothing, the `constructor` property is available to all rabbits through `[[Prototype]]`:
طبیعتاً، اگر کاری انجام ندهیم، ویژگی `constructor` از طریق `[[Prototype]]` برای همه خرگوش‌ها در دسترس است:

```js run
function Rabbit() {}
// by default:
// به صورت پیش‌فرض:
// Rabbit.prototype = { constructor: Rabbit }

let rabbit = new Rabbit(); // inherits from {constructor: Rabbit}
let rabbit = new Rabbit(); // {constructor: Rabbit} ارث می‌برد از

alert(rabbit.constructor == Rabbit); // true (from prototype)
alert(rabbit.constructor == Rabbit); // true (از پروتوتایپ)
```

![](rabbit-prototype-constructor.svg)

We can use `constructor` property to create a new object using the same constructor as the existing one.
می‌توانیم از ویژگی `constructor` برای ایجاد یک شیء جدید با استفاده از سازنده مشابه موجود استفاده کنیم.

Like here:
مثل این نمونه:

```js run
function Rabbit(name) {
this.name = name;
alert(name);
}

let rabbit = new Rabbit("White Rabbit");
let rabbit = new Rabbit("خرگوش سفید");

*!*
let rabbit2 = new rabbit.constructor("Black Rabbit");
let rabbit2 = new rabbit.constructor("خرگوش سیاه");
*/!*
```

That's handy when we have an object, don't know which constructor was used for it (e.g. it comes from a 3rd party library), and we need to create another one of the same kind.
این مفید است زمانی که ما یک شی داریم، نمی‌دانیم از کدام سازنده برای آن استفاده شده است (مثلاً از یک کتابخانه شخص ثالث می‌آید)، و باید یکی دیگر از همان نوع ایجاد کنیم.

But probably the most important thing about `"constructor"` is that...
اما احتمالاً مهمترین چیز در مورد `"constructor"` این است که ...

**...JavaScript itself does not ensure the right `"constructor"` value.**
*** ...خود جاوااسکریپت از مقدار درست `"constructor"` اطمینان نمی‌دهد.**

Yes, it exists in the default `"prototype"` for functions, but that's all. What happens with it later -- is totally on us.
بله، در `"prototype"` پیش‌فرض برای توابع وجود دارد، اما همین. آنچه بعداً با آن اتفاق می افتد - کاملاً به ما بستگی دارد.

In particular, if we replace the default prototype as a whole, then there will be no `"constructor"` in it.
به ویژه، اگر پروتوتایپ پیش‌فرض را به‌طور کلی جایگزین کنیم، `"constructor"` در آن وجود نخواهد داشت.

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

```js run
function Rabbit() {}
Expand All @@ -129,18 +129,18 @@ alert(rabbit.constructor === Rabbit); // false
*/!*
```

So, to keep the right `"constructor"` we can choose to add/remove properties to the default `"prototype"` instead of overwriting it as a whole:
بنابراین، برای حفظ `"constructor"` درست، می‌توانیم به جای بازنویسی به‌عنوان یک کل، ویژگی‌ها را به `"prototype"` پیش‌فرض اضافه یا از آن حذف کنیم:

```js
function Rabbit() {}

// Not overwrite Rabbit.prototype totally
// just add to it
// را به طور کامل بازنویسی نکنید Rabbit.prototype
// فقط به آن اضافه کنید
Rabbit.prototype.jumps = true
// the default Rabbit.prototype.constructor is preserved
// حفظ می‌شود Rabbit.prototype.constructor حالت پیش‌فرض
```

Or, alternatively, recreate the `constructor` property manually:
یا، به طور متناوب، ویژگی `constructor` را به صورت دستی دوباره ایجاد کنید:

```js
Rabbit.prototype = {
Expand All @@ -150,26 +150,26 @@ Rabbit.prototype = {
*/!*
};

// now constructor is also correct, because we added it
// حالا سازنده نیز درست است، زیرا ما دوباره آن را اضافه کردیم
```


## Summary
## خلاصه

In this chapter we briefly described the way of setting a `[[Prototype]]` for objects created via a constructor function. Later we'll see more advanced programming patterns that rely on it.
در این فصل به طور خلاصه نحوه تنظیم `[[Prototype]]` برای اشیاء ایجاد شده از طریق یک تابع سازنده را توضیح دادیم. در آینده شاهد الگوهای برنامه‌نویسی پیشرفته‌تری خواهیم بود که بر آن تکیه دارند.

Everything is quite simple, just a few notes to make things clear:
همه چیز بسیار ساده است، فقط چند نکته برای روشن شدن همه چیز‌ها:

- The `F.prototype` property (don't mistake it for `[[Prototype]]`) sets `[[Prototype]]` of new objects when `new F()` is called.
- The value of `F.prototype` should be either an object or `null`: other values won't work.
- The `"prototype"` property only has such a special effect when set on a constructor function, and invoked with `new`.
- ویژگی `F.prototype` (آن را با `[[Prototype]]` اشتباه نگیرید)، `[[Prototype]]` را برای اشیاء جدید، هنگام فراخوانی `new F()` تنظیم می‌کند.
- مقدار `F.prototype` باید یک شیء یا `null`باشد: مقادیر دیگر کار نمی‌کنند.
- ویژگی `"prototype"` تنها زمانی چنین جلوه خاصی دارد که روی یک تابع سازنده تنظیم شود و با `new` فراخوانی شود.

On regular objects the `prototype` is nothing special:
در اشیاء معمولی `prototype` چیز خاصی نیست:
```js
let user = {
name: "John",
prototype: "Bla-bla" // no magic at all
prototype: "Bla-bla" // به هیچ صورت جادویی نیست
};
```

By default all functions have `F.prototype = { constructor: F }`, so we can get the constructor of an object by accessing its `"constructor"` property.
به‌طور پیش‌فرض همه توابع دارای `F.prototype = { constructor: F }` هستند، بنابراین می‌توانیم سازنده یک شیء را با دسترسی به ویژگی `"constructor"` آن دریافت کنیم.