Skip to content

Native prototypes #68

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 1 commit into from
Aug 24, 2019
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
Expand Up @@ -9,5 +9,5 @@ function f() {
alert("Hello!");
}

f.defer(1000); // shows "Hello!" after 1 sec
f.defer(1000); // montre "Hello!" après 1 seconde
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ importance: 5

---

# Add method "f.defer(ms)" to functions
# Ajouter la méthode "f.defer(ms)" aux fonctions

Add to the prototype of all functions the method `defer(ms)`, that runs the function after `ms` milliseconds.
Ajoutez au prototype de toutes les fonctions la méthode `defer(ms)`, qui exécute la fonction après `ms` millisecondes.

After you do it, such code should work:
Une fois que vous le faites, ce code devrait fonctionner:

```js
function f() {
alert("Hello!");
}

f.defer(1000); // shows "Hello!" after 1 second
f.defer(1000); // montre "Hello!" après 1 seconde
```
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ Function.prototype.defer = function(ms) {
}
};

// check it
// vérifier
function f(a, b) {
alert( a + b );
}

f.defer(1000)(1, 2); // shows 3 after 1 sec
f.defer(1000)(1, 2); // montre 3 après 1 seconde
```
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ importance: 4

---

# Add the decorating "defer()" to functions
# Ajouter la décoration "defer()" aux fonctions

Add to the prototype of all functions the method `defer(ms)`, that returns a wrapper, delaying the call by `ms` milliseconds.
Ajoutez au prototype de toutes les fonctions la méthode `defer(ms)`, qui renvoie un wrapper, retardant l’appel de `ms` millisecondes.

Here's an example of how it should work:
Voici un exemple de la façon dont cela devrait fonctionner:

```js
function f(a, b) {
alert( a + b );
}

f.defer(1000)(1, 2); // shows 3 after 1 second
f.defer(1000)(1, 2); // montre 3 après 1 seconde
```

Please note that the arguments should be passed to the original function.
Veuillez noter que les arguments doivent être passés à la fonction d'origine.
122 changes: 61 additions & 61 deletions 1-js/08-prototypes/03-native-prototypes/article.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@
# Native prototypes
# Prototypes natifs

The `"prototype"` property is widely used by the core of JavaScript itself. All built-in constructor functions use it.
La propriété `"prototype"` est largement utilisée au centre de JavaScript lui-même. Toutes les fonctions constructeurs intégrées l'utilisent.

First we'll see at the details, and then how to use it for adding new capabilities to built-in objects.
Nous verrons d’abord les détails, puis comment l’utiliser pour ajouter de nouvelles fonctionnalités aux objets intégrés.

## Object.prototype

Let's say we output an empty object:
Disons que nous produisons un objet vide:

```js run
let obj = {};
alert( obj ); // "[object Object]" ?
```

Where's the code that generates the string `"[object Object]"`? That's a built-in `toString` method, but where is it? The `obj` is empty!
Où est le code qui génère la chaîne `"[object Object]"`? C'est une méthode `toString` intégrée, mais où est-elle? Le `obj` est vide!

...But the short notation `obj = {}` is the same as `obj = new Object()`, where `Object` is a built-in object constructor function, with its own `prototype` referencing a huge object with `toString` and other methods.
...Mais la notation abrégée `obj = {}` est identique à `obj = new Object()`, `Object` est une fonction constructeur de l'objet intégrée, avec son propre `prototype` référençant un énorme objet avec `toString` et d'autres méthodes.

Here's what's going on:
Voici ce qui se passe:

![](object-prototype.svg)

When `new Object()` is called (or a literal object `{...}` is created), the `[[Prototype]]` of it is set to `Object.prototype` according to the rule that we discussed in the previous chapter:
Lorsque `new Object()` est appelé (ou un objet littéral `{...}` est créé), le `[[Prototype]]` de celui-ci est défini sur `Object.prototype` conformément à la règle dont nous avons parlé dans le chapitre précédent:

![](object-prototype-1.svg)

So then when `obj.toString()` is called the method is taken from `Object.prototype`.
Ainsi, quand on appelle `obj.toString()`, la méthode est extraite de `Object.prototype`.

We can check it like this:
Nous pouvons le vérifier comme ceci:

```js run
let obj = {};
Expand All @@ -36,80 +36,80 @@ alert(obj.__proto__ === Object.prototype); // true
// obj.toString === obj.__proto__.toString == Object.prototype.toString
```

Please note that there is no more `[[Prototype]]` in the chain above `Object.prototype`:
Veuillez noter qu'il n'y a plus de `[[Prototype]]` dans la chaîne au dessus de `Object.prototype`:

```js run
alert(Object.prototype.__proto__); // null
```

## Other built-in prototypes
## Autres prototypes intégrés

Other built-in objects such as `Array`, `Date`, `Function` and others also keep methods in prototypes.
D'autres objets intégrés, tels que `Array`, `Date`, `Function` et autres, conservent également des méthodes dans des prototypes.

For instance, when we create an array `[1, 2, 3]`, the default `new Array()` constructor is used internally. So `Array.prototype` becomes its prototype and provides methods. That's very memory-efficient.
Par exemple, lorsque nous créons un tableau `[1, 2, 3]`, le constructeur `new Array()` par défaut est utilisé en interne. Donc `Array.prototype` devient son prototype et fournit des méthodes. C'est très efficace en mémoire.

By specification, all of the built-in prototypes have `Object.prototype` on the top. That's why some people say that "everything inherits from objects".
Par spécification, tous les prototypes intégrés ont `Object.prototype` en haut. C'est pourquoi certaines personnes disent que "tout hérite d'objets".

Here's the overall picture (for 3 built-ins to fit):
Voici la vue d'ensemble:

![](native-prototypes-classes.svg)

Let's check the prototypes manually:
Vérifions les prototypes manuellement:

```js run
let arr = [1, 2, 3];

// it inherits from Array.prototype?
// il hérite de Array.prototype?
alert( arr.__proto__ === Array.prototype ); // true

// then from Object.prototype?
// puis de Object.prototype?
alert( arr.__proto__.__proto__ === Object.prototype ); // true

// and null on the top.
// et null tout en haut.
alert( arr.__proto__.__proto__.__proto__ ); // null
```

Some methods in prototypes may overlap, for instance, `Array.prototype` has its own `toString` that lists comma-delimited elements:
Certaines méthodes dans les prototypes peuvent se chevaucher, par exemple, `Array.prototype` a son propre `toString` qui répertorie les éléments délimités par des virgules:

```js run
let arr = [1, 2, 3]
alert(arr); // 1,2,3 <-- the result of Array.prototype.toString
alert(arr); // 1,2,3 <-- le résultat de Array.prototype.toString
```

As we've seen before, `Object.prototype` has `toString` as well, but `Array.prototype` is closer in the chain, so the array variant is used.
Comme nous l'avons vu précédemment, `Object.prototype` a aussi `toString`, mais `Array.prototype` est plus proche dans la chaîne, la variante de tableau est donc utilisée.


![](native-prototypes-array-tostring.svg)


In-browser tools like Chrome developer console also show inheritance (`console.dir` may need to be used for built-in objects):
Les outils intégrés au navigateur, tels que la console de développement Chrome, affichent également l'héritage (il faut éventuellement utiliser `console.dir` pour les objets intégrés):

![](console_dir_array.png)

Other built-in objects also work the same way. Even functions -- they are objects of a built-in `Function` constructor, and their methods (`call`/`apply` and others) are taken from `Function.prototype`. Functions have their own `toString` too.
Les autres objets intégrés fonctionnent également de la même manière. Même les fonctions - ce sont des objets d'un constructeur intégré `Function`, et leurs méthodes (`call`/`apply` et autres) sont extraites de `Function.prototype`. Les fonctions ont aussi leur propre `toString`.

```js run
function f() {}

alert(f.__proto__ == Function.prototype); // true
alert(f.__proto__.__proto__ == Object.prototype); // true, inherit from objects
alert(f.__proto__.__proto__ == Object.prototype); // true, hérite d'objets
```

## Primitives

The most intricate thing happens with strings, numbers and booleans.
Une chose complexe se produit avec les chaînes, les nombres et les booléens.

As we remember, they are not objects. But if we try to access their properties, then temporary wrapper objects are created using built-in constructors `String`, `Number`, `Boolean`, they provide the methods and disappear.
Comme on s'en souvient, ce ne sont pas des objets. Mais si nous essayons d'accéder à leurs propriétés, des objets wrapper temporaires sont créés à l'aide des constructeurs intégrés `String`,` Number`, `Boolean`, ils fournissent les méthodes et disparaissent.

These objects are created invisibly to us and most engines optimize them out, but the specification describes it exactly this way. Methods of these objects also reside in prototypes, available as `String.prototype`, `Number.prototype` and `Boolean.prototype`.
Ces objets sont créés de manière invisible pour nous et la plupart des moteurs les optimisent, mais la spécification le décrit exactement de cette façon. Les méthodes de ces objets résident également dans des prototypes, disponibles sous les noms `String.prototype`, `Number.prototype` et `Boolean.prototype`.

```warn header="Values `null` and `undefined` have no object wrappers"
Special values `null` and `undefined` stand apart. They have no object wrappers, so methods and properties are not available for them. And there are no corresponding prototypes too.
```warn header="Les valeurs `null` et `undefined` n'ont pas de wrappers d'objet"
Les valeurs spéciales `null` et `undefined` sont distinctes. Ils n'ont pas de wrapper d'objet, donc les méthodes et les propriétés ne sont pas disponibles pour eux. Et il n'y a pas non plus de prototypes correspondants.
```

## Changing native prototypes [#native-prototype-change]
## Modification des prototypes natifs [#native-prototype-change]

Native prototypes can be modified. For instance, if we add a method to `String.prototype`, it becomes available to all strings:
Les prototypes natifs peuvent être modifiés. Par exemple, si nous ajoutons une méthode à `String.prototype`, elle devient disponible pour toutes les chaînes:

```js run
String.prototype.show = function() {
Expand All @@ -119,32 +119,32 @@ String.prototype.show = function() {
"BOOM!".show(); // BOOM!
```

During the process of development, we may have ideas for new built-in methods we'd like to have, and we may be tempted to add them to native prototypes. But that is generally a bad idea.
Au cours du processus de développement, nous pouvons avoir des idées de nouvelles méthodes intégrées que nous aimerions avoir et nous pourrions être tentés de les ajouter à des prototypes natifs. Mais c'est généralement une mauvaise idée.

```warn
Prototypes are global, so it's easy to get a conflict. If two libraries add a method `String.prototype.show`, then one of them will be overwriting the method of the other.
Les prototypes sont globaux, il est donc facile de créer un conflit. Si deux bibliothèques ajoutent une méthode `String.prototype.show`, l'une d'elles remplacera la méthode de l'autre.

So, generally, modifying a native prototype is considered a bad idea.
Donc, généralement, modifier un prototype natif est considéré comme une mauvaise idée.
```

**In modern programming, there is only one case where modifying native prototypes is approved. That's polyfilling.**
**Dans la programmation moderne, il n'y a qu'un seul cas où la modification de prototypes natifs est approuvée. Le polyfilling.**

Polyfilling is a term for making a substitute for a method that exists in JavaScript specification, but not yet supported by current JavaScript engine.
Le terme Polyfill décrit l'action de faire un substitut à une méthode qui existe dans la spécification JavaScript, mais pas encore pris en charge par le moteur actuel JavaScript.

Then we may implement it manually and populate the built-in prototype with it.
Ensuite, nous pouvons l’implémenter manuellement et y ajouter le prototype intégré.

For instance:
Par exemple:

```js run
if (!String.prototype.repeat) { // if there's no such method
// add it to the prototype
if (!String.prototype.repeat) { // s'il n'y a pas une telle méthode
// ajouter le au prototype

String.prototype.repeat = function(n) {
// repeat the string n times
// répéter la chaîne n fois

// actually, the code should be a little bit more complex than that
// (the full algorithm is in the specification)
// but even an imperfect polyfill is often considered good enough for use
// en fait, le code devrait être un peu plus complexe que cela
// (l'algorithme complet est dans la spécification)
// mais même un polyfill imparfait est souvent considéré comme suffisant pour être utilisé
return new Array(n + 1).join(this);
};
}
Expand All @@ -153,15 +153,15 @@ alert( "La".repeat(3) ); // LaLaLa
```


## Borrowing from prototypes
## Emprunt de prototypes

In the chapter <info:call-apply-decorators#method-borrowing> we talked about method borrowing.
Dans le chapitre <info:call-apply-decorators#method-borrowing> nous avons parlé de l'emprunt de méthode.

That's when we take a method from one object and copy it into another.
C'est quand nous prenons une méthode d'un objet et le copions dans un autre.

Some methods of native prototypes are often borrowed.
Certaines méthodes de prototypes natifs sont souvent empruntés.

For instance, if we're making an array-like object, we may want to copy some `Array` methods to it.
Par exemple, si nous créons un objet semblable à un tableau, nous voudrons peut-être y copier des méthodes `Array`.

E.g.

Expand All @@ -179,18 +179,18 @@ obj.join = Array.prototype.join;
alert( obj.join(',') ); // Hello,world!
```

It works, because the internal algorithm of the built-in `join` method only cares about the correct indexes and the `length` property, it doesn't check that the object is indeed the array. And many built-in methods are like that.
Cela fonctionne car l'algorithme interne de la méthode `join` intégrée ne se préoccupe que des index corrects et de la propriété `length`, il ne vérifie pas que l'objet est bien un tableau. Et beaucoup de méthodes intégrées sont comme ça.

Another possibility is to inherit by setting `obj.__proto__` to `Array.prototype`, so all `Array` methods are automatically available in `obj`.
Une autre possibilité consiste à hériter en fixant `obj.__ proto__` sur `Array.prototype`, afin que toutes les méthodes `Array` soient automatiquement disponibles dans `obj`.

But that's impossible if `obj` already inherits from another object. Remember, we only can inherit from one object at a time.
Mais c'est impossible si `obj` hérite déjà d'un autre objet. N'oubliez pas que nous ne pouvons hériter que d'un objet à la fois.

Borrowing methods is flexible, it allows to mix functionality from different objects if needed.
L'emprunt des méthodes est flexible, cela permet de mélanger la fonctionnalité des objets différents en cas de besoin.

## Summary
## Résumé

- All built-in objects follow the same pattern:
- The methods are stored in the prototype (`Array.prototype`, `Object.prototype`, `Date.prototype` etc).
- The object itself stores only the data (array items, object properties, the date).
- Primitives also store methods in prototypes of wrapper objects: `Number.prototype`, `String.prototype`, `Boolean.prototype`. Only `undefined` and `null` do not have wrapper objects.
- Built-in prototypes can be modified or populated with new methods. But it's not recommended to change them. Probably the only allowable cause is when we add-in a new standard, but not yet supported by the engine JavaScript method.
- Tous les objets intégrés suivent le même schéma:
- Les méthodes sont stockées dans le prototype (`Array.prototype`, `Object.prototype`, `Date.prototype`, etc.).
- L'objet lui-même ne stocke que les données (éléments de tableau, propriétés de l'objet, date).
- Les primitives stockent également des méthodes dans des prototypes d'objets wrapper: `Number.prototype`, `String.prototype`, `Boolean.prototype`. Seuls `undefined` et `null` n'ont pas d'objets wrapper.
- Les prototypes intégrés peuvent être modifiés ou remplis avec de nouvelles méthodes. Mais il n'est pas recommandé de les changer. La seule cause possible est probablement l’ajout d’un nouveau standard, mais pas encore pris en charge par la méthode JavaScript du moteur.