Optimisation du code

a marqué ce sujet comme résolu.
Auteur du sujet

Bonjour,

Suite à une réponse que j'ai obtenu dans un précédent sujet, j'ai découvert les fonctions fléchées. J'ai essayé de les utiliser mais je ne sais pas si ma façon d'écrire du Javascript est correct.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
<!doctype html>
<html>
    <head>
        <title>Interrupteur</title>
        <meta charset="utf-8" />
        <script src="interrupteur.js">
        </script>
    </head>
    <body>
        <p><input id="interrupteur" type="button" value="Interrupteur" /></p>
        <p id="phrase"></p>
    </body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var lumiere = true;

const interrupteur = () => {
    document.getElementById('interrupteur').addEventListener('click', jourNuit);
    swapDayNight();
};

const jourNuit = () => {
    var phrase, fond;
    if (interrupteur) {
        phrase = 'Jour';
        fond = 'yellow';
        lumiere = false;

    }
    else {
        phrase = 'Nuit';
        fond = 'grey';
        lumiere = true;
    }

    document.getElementById('phrase').innerHTML = phrase;
    document.body.style.backgroundColor = fond;
};

onload = interrupteur;

J'avais pensé à séparer le swap du jour et de la nuit des modifications du HTML mais je ne vois pas trop comment faire. Ensuite, je ne suis pas sûr que rendre la variable lumiere globale soit une bonne idée. Enfin, je ne sais pas si mon code est bien fragmenté (ça inclus le premier point) ou si la syntaxe est bonne :euh: .

Merci d'avance pour votre aide.

PS : rien à voir directement mais si il est mieux d'utiliser une balise <button> plutôt qu'<input>, il ne faut pas hésiter à me le dire !

Édité par Helmasaur

+0 -0

Si tu utilises ES6, autant aussi utiliser des classes. Pour éviter d'avoir une variable lumiere globale, tu créés une classe dont lumiere est un attribut et la fonction jourNuit une méthode.

Quelque chose comme:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Interupteur {
  constructor() {
    this.lumiere = true;
  }
  jourNuit() {
    const phrase = {true: 'Jour', false: 'Nuit'};
    const fond = {true: 'yellow', false: 'grey'};

    document.getElementById('phrase').innerHTML = phrase[this.lumiere];
    document.body.style.backgroundColor = fond[this.lumiere];
    this.lumiere = !this.lumiere;
  }
}

const interrupteur = new Interrupteur();
onloud = () => {
  document.getElementById('interrupteur')
          .addEventListener('click', interrupteur.jourNuit.bind(interrupteur));
};

Le .bind(interrupteur) est important. Il vient du fait que la manière dont les classes sont gérés en javascript est assez particulière.

Pour faire simple, this correspond à l'objet dont provient la fonction appelé au moment de l'appel et bind permet de forcer cette valeur. Petit exemple:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
var x = "x";
var obj = {
  x: "obj",
  getX() { return this.x; }
};
var obj2 = {
  x: "obj2"
};

obj.getX(); // "obj"
var getX = obj.getX;
getX(); // "x", la fonction ne provient pas d'un objet donc this correspond à window
obj2.getX = obj.getX;
obj2.getX(); // "obj2"
obj2.getX = obj.getX.bind(obj);
obj2.getX(); // "obj", bind a forcé this à être obj
getX = obj.getX.bind(obj2);
getX(); // "obj2", bind a forcé this à être obj2
obj.getX = getX;
obj.getX(); // "obj2", toujours à cause du bind
+0 -0
Auteur du sujet

Je ne savais pas que les classes avaient faites leur apparition dans Javascript. C'est une très bonne chose !

Au niveau de la méthode bind, si j'ai bien compris, on change l'objet à laquelle this pointe ? Enfin, je voulais savoir dans quelles cas il fallait mieux utiliser les fonctions fléchées.

Dans tous les cas, merci pour la réponse :) .

Édité par Helmasaur

+0 -0

Je ne savais pas que les classes avaient faites leur apparition dans Javascript. C'est une très bonne chose !

Je ne suis pas sur que ça soit une bonne chose, les classes en JS sont simplement du sucre syntaxiques pour rendre les choses plus faciles. Mais ça fonctionne exactement comme avant avec un modèle prototypale. Il est donc important de comprendre un minimum comment fonctionne l'héritage prototypal avant d'utiliser les classes en js.

Le problème de l'objet en js est que comme tu vois là on se retrouve avec un this qui point vers n'importe quoi et qu'on doit rebinder au contexte souhaité, ce qui est pénible et source de bugs difficiles à detecter si on ne fait pas attention. Tu peux d'ailleurs éviter le bind en utilisant une… fonction fléchée !

Un bon exercice pour toi serait de re-écrire ce code dans une approche plus fonctionnelle, sans utiliser le mot clef "this".

Voici une très bonne vidéo qui explique le problème du this et comment on peut faire autrement via la programmation fonctionnelle et les factories. :)

“Your manuscript is both good and original. But the part that is good is not original, and the part that is original is not good.” Attributed to Samuel Johnson

+0 -0
Auteur du sujet

Je commence à comprendre l'intérêt d'écrire du code fonctionnel. Je n'ai pas encore réécrit mon script car je souhaite avoir des retours sur ce que j'ai fait et surtout une interrogation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
<!doctype html>
<html>
    <head>
        <title>Machine à remonter le temps</title>
        <meta charset="utf-8" />
        <script src="machine.js"></script>
    </head>
    <body>
        <head>
        </head>
        <main>
            <p>Il est <span id="time"></span>.</p>
            <p><input id="machine" type="button" value="Machine à remonter le temps" /></p>
            <p id="sentence"></p>
        </main>
    </body>
</html>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Country {
    constructor() {
        this.isDay();
        this.naturalTime = true;
        this.clock = new Clock();
    }

    switchDayNight() {
        const background = {true: 'yellow', false: 'grey'};
        document.body.style.backgroundColor = background[this.day];
        this.day = !this.day;
    }

    isDay() {
        this.day = new Date().getHours() < 18 && new Date().getHours() > 8 ? true : false;
    }
}

class Clock {
    setTime() {
        document.getElementById('time').innerHTML = new Date().toLocaleTimeString();
    }
}

const country = new Country();

onload = () => {
    document.getElementById('machine')
            .addEventListener('click', function() {
                country.switchDayNight();
                country.naturalTime = false;
            });
    country.switchDayNight();
    country.clock.setTime();
    setInterval(country.clock.setTime, 1000);
};

Mon objectif est d'afficher un fond sombre quand l'heure de l'ordinateur est entre 18 et 8 heures, sinon, afficher un fond clair. Quand on click sur le bouton, je souhaite mettre l'heure à 8 heures s'il faut nuit et à 18 heures s'il fait jour. Je précise que je veux que les secondes défilent.

+0 -0
Auteur du sujet

Je me permets de répondre à la suite de mon précédent message. J'ai avancé au niveau Javascript. Je ne pense pas que l'écriture est idéale mais c'est pour savoir si je suis dans la bonne direction. Il reste à rajouter un nouveau setInterval qui débute quand on clique sur le bouton afin que l'heure continue de défiler.

Je pense qu'il faudrait isoler setInterval dans une méthode de Clock une fois qu'on l'utilise après l'appuie sur le bouton.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
class Country {
    constructor() {
        this.isDay();
        this.clock = new Clock();
    }

    switchDayNight() {
        if (this.day) {
            this.clock.setNight();
        }
        else {
            this.clock.setDay();
        }

        this.setWorld(this.day, this.clock.date);
        this.day = !this.day;
    }

    isDay() {
        this.day = new Date().getHours() < 18 && new Date().getHours() > 8 ? true : false;
    }

    setWorld(day, time) {
        const background = {true: 'yellow', false: 'grey'};

        document.body.style.backgroundColor = background[day];
        document.getElementById('time').innerHTML = time;

    }
}

class Clock {
    constructor() {
        this.date = new Date().toLocaleTimeString();
    }

    setTime() {
        this.date = new Date().toLocaleTimeString();
    }

    setDay() { // TODO Changer l'affichage
        this.date = new Date();
        this.date.setHours(8);
        this.date.setMinutes(0);
        this.date.setSeconds(0);
    }

    setNight() { // TODO Changer l'affichage
        this.date = new Date();
        this.date.setHours(18);
        this.date.setMinutes(0);
        this.date.setSeconds(0);
    }
}

const country = new country();

onload = () => {
    document.getElementById('machine')
            .addEventListener('click', function() {
                country.switchDayNight();
                clearInterval(clock);
            });

    country.setWorld(country.day, country.clock.date);
    var clock = setInterval(function() {
        country.clock.setTime();
        setWorld(hyrule.date, hyrule.gossipStone.date);
    }, 1000);
};

Édité par Helmasaur

+0 -0
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

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