Ok, alors c’est officiel, les fonctions sont des objets, mais des objets avec une capacité spéciale : on peut les invoquer. Et comme il est indiqué dans le lien que Sylvain a donné, cette capacité « d’invocabilité » est étroitement liée avec le fait que les fonctions ont une valeur typeof prévues spécialement pour elles.
Pour être honnête, j’ai été un peu retors en utilisant typeof dans mon argumentation. En réalité je me sers rarement de cet opérateur, et ce n’est même pas parce qu’il est mal foutu : simplement, j’ai rarement besoin de détecter le type de mes valeurs dans les applications que je développe.
Mais si ça ne tenait qu’à moi, je changerais typeof pour le rendre un peu plus utile. Déjà, je corrigerais l’énormité de typeof null qui renvoie "object" ; et il aurait aussi des valeurs spécifiques pour les autres constructeurs natifs du langage, en particulier Array et RegExp qui ont une syntaxe littérale.
Bien sûr tout ça n’arrivera pas, car trop d’ancien code sur le Web repose sur le comportement actuel de typeof, et changer ce comportement serait casser une partie du Web, une partie dont la taille est difficile à mesurer, mais sans doute très grande.
À propos de constructeurs natifs,
Date a une place toute spéciale dans mon cœur, et je sais que ça a déjà été discuté au moins une fois sur ce forum : il se comporte tantôt comme un constructeur, tantôt comme une fonction, selon qu’on utilise
new ou pas. Je ne vais pas rentrer dans les détails mais essayez vous-mêmes, vous allez voir c’est merveilleux.
Comme il est conseillé dans tous les guides JavaScript de tous les Internets, il faut bien entendu écrire des constructeurs qui renvoient une valeur différente quand ils sont invoqués sans
new. D’ailleurs je pense que c’est pour ça que l’opérateur… Non, la propriété… Enfin, le « truc »
new.target a été inventé. Ce petit bijou est une merveille d’élégance syntaxique. (Pour celles et ceux qui ont un doute, ce paragraphe entier est sarcastique

)
Je suis également tenté de donner une valeur typeof pour les constructeurs non natifs (je pense notamment à ceux du DOM). Quelque chose comme "NonNativeObject" pourraît s’avérer utile. Ça nous assure déjà que ce n’est pas null, et nous permet d’enchaîner derrière avec instanceof ou isPrototypeOf, ou des moyens fournis par le DOM lui-même (là je pense par exemple à la propriété node.nodeType, qui est un des moyens de déterminer si un nœud est une instance de Element ou de Text, entre autres).
@Loralina, le lien que tu donnes présente aussi, de manière très intéressante, la différence entre un type primitif et un objet :
1 2 3
| var five = 5;
five.three = 3;
console.log(five + five.three); // devinez |
On peut attacher des propriétés sur une fonction, ce qui ajoute encore une preuve que ce sont des objets.
1 2 3
| function uneFonction() {}
uneFonction.uneProp = "une valeur";
console.log(uneFonction.uneProp); |
Une autre chose que l’article de Bruno Lesieur m’a fait réaliser, c’est ce qui se passe quand on écrit :
Le nombre 42 étant un primitif, il n’a pas de méthode .toFixed — à vrai dire il n’a aucune méthode, ni aucune propriété, car ce n’est pas un objet. Mais alors, comment l’instruction ci-dessus peut-elle retourner 42.00 ?
C’est parce que le nombre est converti en une valeur intermédiaire new Number(42), une valeur encapsulée, qui est donc de type objet et qui a les méthodes de Number.prototype.
Cela répond à une question que je m’étais posée, « pourquoi diable peut-on encapsuler des valeurs, à quoi cela sert-il à part à être un des pièges idiots du langage ? »
La réponse est : « c’est le mécanisme qui permet aux types primitifs d’avoir des méthodes, et qui permet aux développeuses et développeurs d’enrichir les prototypes de ces mêmes types primitifs, même si c’est déconseillé par ailleurs. »
Partager