Pourquoi les fonctions ne sont pas des objets comme les autres ?

Pourquoi les fonctions ne passent-elles pas comme références alors que ce sont des objets ?

Le problème exposé dans ce sujet a été résolu.

Bonjour à tous !

Je sollicite votre aide pour répondre à une question qui me turlupine sur les objets et les fonctions en javascript. On est bien d'accord que les fonctions sont des objets, ce sont même des objets de première classe.

On sait aussi que normalement une variable qui contient un objet est une simple référence vers cet objet et ne contient pas l'objet lui-même. Le code suivant tout ce qu'il y a de plus classique :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// on créer un objet napoleon
var george = {
    prenom : "Bonaparte",
    nom : "Napoléon"
};
// on créer une variable imposteur et on lui affecte l'objet napoleon
var imposteur = napoleon;
// on modifie le prenom de notre imposteur :
imposteur.prenom = "Didier";

console.log(imposteur.prenom); // affiche bien "Didier"
console.log(napoleon.prenom); // affiche aussi "Didier" car référence vers le même objet

Jusque là, tout est normal. J'ai donc essayé de faire pareil avec des fonctions. Et là c'est le drame :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// on créer une fonction anonyme affectée à une variable bonjour
var bonjour = function () {
    console.log("bonjour");
};
// on affecte cette fonction à une nouvelle variable bonsoir
var bonsoir = bonjour;
bonsoir(); // affiche bien "bonjour";

// on modifie la fonction d'origine bonjour
bonjour = function () {
    console.log("bonsoir");
};

bonjour(); // affiche bien "bonsoir"
bonsoir(); // affiche toujours "bonjour" !!!

Manifestement notre fonction bonjour est affectée en valeur et non en référence à la variable bonsoir, ce qui explique que cette dernière n'est pas affectée par le changement. Pourtant les fonctions étant des objets, elles ne devraient pas avoir ce comportement si ? Les tableaux par exemple se comportent "correctement", c'est à dire comme des objets.

Savez vous pourquoi un tel comportement ? Existe-il d'autres objets à se comporter ainsi ?

+0 -0

Salut,

Sans être expert en Javascript, je vois bien deux comportements différents :

  • dans le premier, tu appelles ton objet via une référence, prend un paramètre et le modifie.
  • dans le deuxième, tu crées un nouvel objet, et tu écrases la référence contenue dans la variable par ce nouvel objet.

Merci pour ton intervention, tu m'as mis sur la piste ! J'ai enfin retrouvé comment utiliser le passage pas référence des fonctions :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
function bonjour() {
    console.log("Bonjour");
}
var bonsoir = bonjour;

// on redéfini la fonction
function bonjour() {
    console.log("bonsoir");
}

bonsoir(); // affiche bien bonsoir !

C'est un peu subtile en fait je trouve. Dans le 1er cas (message précédent) ma variable contient une référence vers une fonction anonyme. J'affecte cette référence à une autre variable. Puis je modifie ma 1ére variable pour la faire pointer vers une autre fonction. Il est en fait impossible de modifier la fonction anonyme elle même car on ne peut pas y accéder…

EDIT : ce code n'a rien à voir avec les références, c'est simplement un bête hoisting de la fonction…

+0 -0

Personnellement, je trouve le premier comportement parfaitement logique, par contre le second semble bien plus subtil et je ne saurais exactement dire quel mécanisme est en jeu (en revanche, je peux dire que ce ne sera pas forcement le cas dans d'autres langages comme python).

EDIT: je viens de tester sous chrome, et si j’évalue les expressions une a une, ça ne fonctionne pas comme tu le décris.

Hum oui tu as raison et je viens de comprendre pourquoi :

C'est a cause du hoisting ! Mon second code ne fonctionne absolument pas comme je l'avais décris précédemment ! C'est bien plus simple que ça. En js, les fonctions sont hissées en haut de la portée de déclaration ce qui les rend utilisable avant leur déclaration.

Ici la redéfinition de la fonction vient simplement écraser la première définition de la fonction, et cette nouvelle fonction redéfinie est hissée en haut du code, puis affectée à l’exécution à la variable bonsoir. Rien à voir avec un quelconque passage en référence comme j'ai pu le croire… :(

C'est pour ça que si tu évalue les expressions les unes après les autres ça casse ne fonctionne plus ! (ça casse probablement le hoisting de la fonction redéfinie).

Si on appel bonsoir() avant la redéfinition de la fonction, on voit bien l'effet du hoisting : il affiche bonsoir au lieu de bonjour.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
function bonjour() {
    console.log("Bonjour");
}
var bonsoir = bonjour;

bonsoir(); // affiche bonsoir à cause du hoisting
// on redéfini la fonction
function bonjour() {
    console.log("Bonsoir");
}

Bon du coup on sait pourquoi les deux codes que j'ai donné fonctionnent ainsi (le premier car on écrase les références, le second à cause du hoisting), mais je ne vois toujours pas comment passer une fonction en référence du coup… :p Peut-être que ce n'est tout simplement pas possible de le faire de la même façon que quand on manipule des objets…

+0 -0

Je n'ai pas bien compris la problématique, tu pourrais préciser ce que tu cherche a faire stp ?

Je cherche à utiliser le fait que les fonctions sont des objets et donc à les manipuler comme références. Dans l'idée affecter une fonction1 à une variable2, modifier la fonction2 et voir que cela se répercute sur la variable2.

Je voulais à la base faire une manipulation du genre pour "prouver" que les fonctions sont bien des objets et qu'elles ont le même comportement.

Mais je crois que je fais fausse route :

  • les fonctions anonymes ne sont à priori pas modifiables car on n'a rien pour les atteindre. Dans mon premier code par exemple on va juste écraser les références vers laquelle la variable pointe mais on ne peut pas modifier la fonction anonyme directement. On ne peut pas aller en mémoire où la fonction anonyme est stocké et modifier le corps de la fonction.
  • les fonctions déclarées avec un nom se comportent bien comme je veux mais c'est à cause du hoising et non du fait ce que sont des objets. C'est juste un comportement particulier de fonctions.
  • les fonctions fléchés (ES6) ne pourront clairement pas faire mieux de même que les fonctions nommées affectés à une variable.

Du coup je crois qu'il n'a pas vraiment de solution. ^^

+0 -0

Si, les fonctions sont bien des objets comme les autres. Simplement, on ne peut pas modifier le code d'une fonction. Par contre on peut lui ajouter des attributs, de la même manière que si on avait des autres objets:

1
2
3
4
var f = function(){ console.log('Salut!'); };
var g = f;
g.tralala = 42;
console.log(f.tralala); // 42
+0 -0

J'avoue que je n'avais pas pensé à passer par les propriétés pour contourner le problème de la modification impossible du code de la fonction. En procédant ainsi on peut en effet facilement faire le parallèle avec les objets ! Merci à toi :)

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte