IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JavaScript Discussion :

Optimisation POO et sécurité en JS


Sujet :

JavaScript

  1. #1
    Membre du Club
    Inscrit en
    Juin 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Juin 2003
    Messages : 71
    Points : 54
    Points
    54
    Par défaut Optimisation POO et sécurité en JS
    Bonjour,

    Pour la réalisation d'un futur projet, je vais devoir (ré)apprendre à coder en javascript. Les "best-practices" et le langage ayant évolués avec les années, je dois me (re)mettre à niveau.

    Le web ne manque pas d'informations valables, mais... il est facile de tomber également sur des informations erronées/désuètes/ou tout simplement fausses. Ci-dessous quelques classes que j'ai écrite pour me faire un petit exercice. Je sollicite donc l'avis des plus expérimentés qui découvriront au fil des commentaires de mon code les questions que je me pose.

    Mes 2 principaux objectifs sont les suivants :
    • La sécurité
    • L'optimisation (par exemple : éviter les objets "closures")


    Voici mes classes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    /* CLASS caracteristiques
     * Comportes des variables et méthodes utiles à d'autres CLASS
     * (cf. CLASS humain et CLASS animal
     */
    var caracteristiques = function() {
    	this.attaque = 0;
    	this.defense = 0;
    };
    caracteristiques.prototype.setAttaque = function(attaque) {
    	this.attaque = attaque;
    };
    caracteristiques.prototype.setDefense = function(defense) {
    	this.defense = defense;
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    /* CLASS animal
     * C'est une CLASS parente
     * (cf. CLASS animalOurs ou animalLoup)
     */
    var animal = function(nom) {
    	this.nom = nom;
    	this.niveau = 1;
    	this.caracteristiques = new caracteristiques();
    	/*QUESTION : a chaque nouvel objet enfant hérité de la CLASS "animal", comment se comporte la variable "this.caracteristiques"? contiendra-t-elle un objet "closure" ? Y a-t-il une meilleure manière de faire en terme de mémoire ? */
    };
    animal.prototype.toString = function() {
    	return(this.nom);
    };
     
    /* CLASS animalOurs
     *
     */
    var animalOurs = function(nom) {
    	animal.call(this, nom?nom:"Ours");
    	this.caracteristiques.setDefense(3);
    };
    animalOurs.prototype = new animal();
    animalOurs.prototype.constructor = animalOurs;
     
    /* CLASS animalOurs
     *
     */
    var animalLoup = function(nom) {
    	animal.call(this, nom?nom:"Loup");
    	this.caracteristiques.setDefense(1);
    };
    animalLoup.prototype = new animal();
    animalLoup.prototype.constructor = animalLoup;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
     
    /* CLASS humain
     * 
     */
    var humain = function(nom, prenom) {
    	this.nom = nom;
    	this.prenom = prenom;
    	this.caracteristiques = new caracteristiques();
    	this.animauxInvoques=[]; 
    	/*QUESTION : "this.animauxInvoques" est un tableau d'objet. Comment javascript s'en sort-il ? Stock-t-il juste un pointer vers les objets ou copie-t-il l'objet au total ? Y a-t-il une meilleure manière de faire en terme de mémoire/performance ? */
    };
    /* cette méthode permet d'ajouter un animal à un humain */
    humain.prototype.invoqueAnimal = function(animalClassName) {
    	var newAnimal = new window[animalClassName]();
    	this.animauxInvoques.push(newAnimal);
    	return newAnimal;
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    /* programme principal */
    var game = function()
    {
    	var gameName = "Game name";
    	var humain1 = new humain("Smith", "John");
    	var humain2 = new humain("Hollande", "Angella");
     
    	humain1.caracteristiques.setAttaque(2);
     
    	var newAnimal = humain2.invoqueAnimal("animalOurs");
    	newAnimal.caracteristiques.setAttaque(5);
     
    	var newAnimal = humain2.invoqueAnimal("animalLoup");
    	newAnimal.caracteristiques.setAttaque(1);
    };
    (function() {
    	var g = new game();
    	/* QUESTION : En procédant de cette manière, est-ce que j'empêche l'appel et l’exécution de mes objets depuis un script externe ?*/
    })();
    Je remercie d'avance ceux qui auront eu la gentillesse de lire mon poste.
    Cordialement,
    Greg

  2. #2
    Rédacteur/Modérateur

    Avatar de SpaceFrog
    Homme Profil pro
    Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Inscrit en
    Mars 2002
    Messages
    39 640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2002
    Messages : 39 640
    Points : 66 669
    Points
    66 669
    Billets dans le blog
    1
    Par défaut
    optimisation ... je veux bien .

    par contre a quel niveau intervient ton besoin de sécurité ?

  3. #3
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    C'est quoi ça un objet closure ?
    Une closure est une fonction utilisée pour isoler le scope de variables, pour les rendre "privées" en somme. C'est ce que tu fais avec ta variable g dans ton dernier code. Ce n'est pas quelque-chose à éviter, si on les utilise c'est qu'il y a de bonnes raisons !

  4. #4
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    Qu'entends tu par objets "closures" ? Et pourquoi veux-tu les éviter ?

    - Par convention, les fonctions faisant office de "constructeurs d'instance" commencent par une majuscule. (par exemple caracteristiques)
    - Question 1 : à chaque nouvel animal, tu vas créer un nouvel objet construit à partir de caractéristique. Donc, chaque instance d'animal aura son propre objet caractéristique. Ils ne se partageront pas un objet commun. Au contraire, setAttaque étant de la propriété "prototype", elle sera commune à chaque instance d'Animal.
    - Question 2 : pour tout ce qui n'est pas "primitif", JavaScript stocke une référence. Donc :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var monObj1 = [];
    var monObj2 = monObj1;
    monObj2.push('coucou');
    console.log(monObj1); // affiche 'coucou' car monObj1 et monObj2 pointent à la même adresse
    Au contraire :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    var monPrimitif1 = 5;
    var monPrimitif2 = monPrimitif1;
    monPrimitif2 = 'coucou';
    console.log(monPrimitif1); // affiche 5
    - Question 3 : Oui et non. Ce que tu utilises est le pattern module. En gros, tout ce qui sera défini à l'intérieur de cette fonction immédiatement invoquée (IIFE en anglais) ne sera pas visible par les scripts externes. Donc, il faut que tu encapsules aussi toutes tes "pseudo classes". Si tu veux néanmoins rendre disponibles des fonctions, il faut attacher l'instance de game à l'objet global (window dans les navigateurs) :
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    (function(){
     
    var maVarPrivee = 1337;
     
    var maFonctionPrivee = function maFonctionPrivee() {
      console.log("On ne peut pas m'appeler via l'objet global window (à l'extérieur du module)");
    }
     
    app.maFonctionPublique = function maFonctionPublique() {
      maFonctionPrivee();
      return maVarPrivee;
    };
     
    }(window.app = window.app || {})); // app sera la seule variable accessible dans l'objet global window
     
    // On peut appeler la fonction publique
    app.maFonctionPublique(); // retourne 1337 et log "On ne peut pas m'appeler via l'objet global window (à l'extérieur du module)"

    Enfin, tu utilises l'héritage "pseudo classique" pour créer tes objets. J'opterais plutôt pour l'héritage orienté prototype. J'en parle ici.

  5. #5
    Membre du Club
    Inscrit en
    Juin 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Juin 2003
    Messages : 71
    Points : 54
    Points
    54
    Par défaut
    Merci à vous 2 pour vos réponses.

    Pour répondre à Sylvain au sujet de "closure":
    Pourquoi est-il conseillé d'utiliser la méthode "prototype" plutôt que la méthode "closure" ?

    C'est principalement une question de performances. Lors de la création d'un objet "closure", le constructeur est parsé/executé, il y a donc création des différentes méthodes qui appartiennent alors à l'instance de l'objet. Avec une classe "prototype" les méthodes sont déjà instanciées lors de la création du type et appartiennent à l'instance du prototype de l'objet, deux instances d'une même classe partagent le même prototype. Cela a deux incidences :

    • La création de l'objet sera plus longue à cause de la création des méthodes membres.
    • L'instance de l'objet prendra plus de mémoire car les méthodes membres ne sont pas partagées entre les objets.
    Je dois être attentif aux performances de l'application. Pour en revenir à mes besoins et garder les quelques lignes de codes que j'ai indiquées plus haut, ce n'est pas 2 objets de ma CLASS "humain" avec 2 objets animaux (animalOurs et animalLoup) qui vont être lourd à charger. A terme, l'interface doit pouvoir charger en une seule fois une bonne dizaine de millier d'objets "humain" avec pour chacun une 100ène d'animaux (10'000 * ~100 => 1 millions d'objets avec chacun des caractéristiques différentes). D'où l'importance de savoir comment Javascript gère mes variables et mes objets.

    Pour répondre à SpaceFrog :
    Je ne sais pas encore trop de quoi me méfier au niveau sécurité avec Javascript.

    J'effectuerais des requêtes AJAX qui modifieront des informations dans la base de donnée. Je pense donc à des risques de XSS et par extension à des CSRF. Évidement, je serais vigilant sur la partie serveur, mais je préfaire multiplier les gardes-fous à tout les niveaux (JS compris).

    Par rapport aux quelques lignes que j'ai présenté plus haut, j'aimerais déjà pouvoir "encapsuler" de manière sécurisée mes objets et mes méthodes, quelles ne soient pas accessibles depuis un script externe. Je sais déjà que ce n'est pas bon, puisque j'ai trouvé un moyen de contourné le code que j'ai écrit. Voilà donc le genre de conseils que je cherche.

    Cordialement,
    Greg

    EDIT : ma répondre c'est croisée avec celle de Kaamo... je vais lire ton poste dans la minute

  6. #6
    Rédacteur/Modérateur

    Avatar de SpaceFrog
    Homme Profil pro
    Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Inscrit en
    Mars 2002
    Messages
    39 640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2002
    Messages : 39 640
    Points : 66 669
    Points
    66 669
    Billets dans le blog
    1
    Par défaut
    Pour répondre à SpaceFrog :
    Je ne sais pas encore trop de quoi me méfier au niveau sécurité avec Javascript.
    De tout ...
    la sécurité n'existe pas avec javascript

  7. #7
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Points : 3 966
    Points
    3 966
    Par défaut
    De ce que j'apprends sur le sujet, en principe le strict respect des principes de base de la programmation POO permet de construire des applis sures ou sécuritaires.

    Je n'ai pas hélas à ce stade le recul suffisant ni les compétences pour défendre ces concepts.

    Cette dernière phrase est plutôt troublante SpaceFrog, et doit certainement s'appliquer de la même façon à tous les langages.

    Gregco, puisque tu parles de script externe, tu peux regarder du coté de Google Caja :
    https://developers.google.com/caja/docs/about/

    et du coté de adsafe :
    http://www.adsafe.org/

  8. #8
    Rédacteur/Modérateur

    Avatar de SpaceFrog
    Homme Profil pro
    Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Inscrit en
    Mars 2002
    Messages
    39 640
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 74
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur Web Php Mysql Html Javascript CSS Apache - Intégrateur - Bidouilleur SharePoint
    Secteur : Industrie

    Informations forums :
    Inscription : Mars 2002
    Messages : 39 640
    Points : 66 669
    Points
    66 669
    Billets dans le blog
    1
    Par défaut
    Javascript est un langage client totalement ouvert et accessible par le client.
    il est visible en clair dans les consoles, dans lesquelles on peut directement injecter du javascript. L'obfuscation du code ne représente pas une barrière énorme, juste une étape supplémentaire et un peu plus de temps de compréhension du code.

    Ce qui m'amène à dire que "POO" ou pas la sécurité n'est pas de mise avec javascript.

  9. #9
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Points : 3 966
    Points
    3 966
    Par défaut
    Tu risques de me sortir toutes les banalités que je connais comme toi à ce sujet, les ayant ressassées et ressassées comme toi et les considérant comme toi comme des évidences ou des vérités.

    Je n'ai malheureusement pas les moyens de discuter une vision contraire des choses avec l'intelligence requise néanmoins quelques éléments de base peuvent s'appliquer :

    l'obfuscation n'est pas de la sécurité, c'est de l'obfuscation.

    quel est le lecteur de ce code source ? de quelle sécurité parle t'on ? est ce l'utilisateur du script ? est ce sa sécurité ou la sécurité de ses informations ? est-ce la sécurité du service ?

    L'une des grandes problématiques de la "sécurité", au demeurant un concept très vague, est de garantir une certaine confidentialité des échanges entre un service et son usager. Il me semble que Gregco pose bien le problème à la base en évoquant le notion de tiers, par le biais de script externe.

    Pourrais tu préciser ce que tu entends par cette absence totale de sécurité ?

    S'il m'est donné de lire le code source JS ou autre du web browser de mon voisin, accéder les variables et leurs valeurs de l'appli qu'utilise mon voisin, le problème de sécurité tiendra t'il à JS ou à d'autres problèmes en amont ?

    S'il m'est donné de lire le code source de mon propre web browser, pouvant par là accéder des infos qui en principe ne concerne que moi, où est le problème de sécurité ?

  10. #10
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    SpaceFrog veut simplement dire, je pense, que l'utilisateur pourra faire ce qu'il veut avec le code JavaScript.

    JavaScript s'exécute sur le poste client.
    L'utilisateur est le seul maître à bord sur son poste.

    Ce qu'il faut faire, c'est se blinder côté serveur.

    - L'obfuscation/minification étant là respectivement pour éviter un retro-engineering trop simple et pour des soucis de performances.
    - Pour éviter les collisions avec d'autres scripts externes, il faut mettre son code utile dans une seule "variable globale" (comprendre qui sera stockée dans l'objet global window) en utilisant, par exemple, le module pattern.

  11. #11
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    Pour revenir sur le sujet des closures et du lien donné, je trouve l'auteur très maladroit dans son vocabulaire. Ce qu'il appelle "méthode closure" et "méthode prototype", c'est simplement choisir entre attacher une fonction au prototype ou à l'instance. Ce n'est pas qu'une histoire de performances, ça n'a juste pas de sens de donner une méthode individuellement à chaque instance si on veut faire de la POO. Je te suggère de trouver un autre guide plus récent et relu par plusieurs personnes.

    Un exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    var Foo = function(){
        this.method = function(){
            return 'test'; 
        }
    }
     
    var a= new Foo();
    var b= new Foo();
     
    a.method = function(){ return 'autre test'; };
    a.method() //autre test
    b.method() //test ! mais je croyais que method était une méthode de classe
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    var Foo = function(){};
    Foo.prototype.method = function(){
        return 'test'; 
    }
     
    var a= new Foo();
    var b= new Foo();
     
    Foo.prototype.method = function(){ return 'autre test'; };
    a.method() //autre test
    b.method() //autre test, toutes les instances interrogent la même fonction
    Cette différence de conception n'est pas directement liée aux closures, on aurait pu se débrouiller pour faire la même chose sans closure. Retiens simplement que si tu veux manipuler des simili-classes en JS, il faut effectivement mettre à profit les prototypes. Même si selon moi, penser en termes de classes dans un langage de programmation orientée prototype est une erreur.

    Et question sécurité il faut juste retenir que c'est le serveur qui joue le rôle d'autorité. Il décide de tout et ne fait jamais confiance au client.

  12. #12
    Membre extrêmement actif
    Profil pro
    Inscrit en
    Décembre 2003
    Messages
    1 616
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2003
    Messages : 1 616
    Points : 3 966
    Points
    3 966
    Par défaut
    Citation Envoyé par Kaamo Voir le message
    SpaceFrog veut simplement dire, je pense, que l'utilisateur pourra faire ce qu'il veut avec le code JavaScript.

    JavaScript s'exécute sur le poste client.
    L'utilisateur est le seul maître à bord sur son poste.

    Ce qu'il faut faire, c'est se blinder côté serveur.
    Mais je suggère la même chose, seulement si les failles existent coté serveur, en quoi le javascript en tant que langage ou dans son environnement d'exécution (le web browser) peut il être mis en cause ?

    Si le programmeur met à disposition des infos, des données, des objets dans leur entier qui ne devraient pas être dans les mains du client, ni sur son écran ou dans son code source, en quoi le javascript est il incriminable ? Et donc de quelle sécurité parle t'on ? celle du service ?

    la sécurité existe avec javascript, c'est un élément de la chaîne de sécurité comme un autre. Dire que la sécurité n'existe pas avec javascript, c'est balancer des lieux communs qui permettent de ne pas se poser les (bonnes) questions.

    Quand aux collisions, la problématique est beaucoup plus vaste, d'un point de vue sécurité. C'est tout l'intérêt d'outils comme caja ou adsafe.

    Exemple simple, mais si je veux pénétrer un site qui affiche de la pub sur ses parties privatives, il y a de grandes chances qu'en achetant un peu d’espace pub sur ce site par le biais d'un broker quelconque, je puisse faire passer mon propre code javascript sur ce site, et si mon script n'est pas passé par une moulinette adsafe ou caja, il y a des chances que j'ai avec ce script full access au DOM ainsi qu'à l'objet global, avec le potentiel insécuritaire que cela représente.

    moi cette phrase me choque :
    la sécurité n'existe pas avec javascript
    Je me suis même amusé à traduire un mec, Marc Stiegler en l’occurrence, qui discute de cette problématique là avec intelligence et simplicité (toute relative).
    En tout cas selon lui et d'autres comme Mark Miller de Google, il y a beaucoup de "bonnes choses" dans le javascript, notamment le fait que ce soit OO, presque dans sa globalité. Tout ce qui n'est pas OO est source de failles potentielles, dans une perspective modulaire.

  13. #13
    Membre du Club
    Inscrit en
    Juin 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Juin 2003
    Messages : 71
    Points : 54
    Points
    54
    Par défaut
    Un grand merci pour vos réponses, qui me donne matières à lire/comprendre.

    Citation Envoyé par Kaamo
    Par convention, les fonctions faisant office de "constructeurs d'instance" commencent par une majuscule. (par exemple caracteristiques)
    C'est noté

    Citation Envoyé par Kaamo
    Question 1 : à chaque nouvel animal, tu vas créer un nouvel objet construit à partir de caractéristique. Donc, chaque instance d'animal aura son propre objet caractéristique. Ils ne se partageront pas un objet commun. Au contraire, setAttaque étant de la propriété "prototype", elle sera commune à chaque instance d'Animal.
    Y a-t-il un moyen pour être plus performant ? En créant la class Caracteristiques je souhaitais pouvoir ajouter des variables (avec valeurs prédéfinies) et des méthodes à d'autres class (Humain, Animal et les class enfants). Vous allez me dire qu'il suffit simplement de faire hériter mes class Humain et Animal de Caracteristiques, mais je ne le souhaite pas. Le but de l'exercice est de trouver une manière de faire de l'héritage multiple. Javascript bossant simplement avec des Objets, je me dis qu'il y a certainement un moyen d'y arriver... non ? En tout cas sekaijin semble le laisse sous-entendre :
    http://www.developpez.net/forums/d13...t/#post7511485
    Je n'ai pas encore eu le temps de chercher la solution, mais je le ferais demain.

    Citation Envoyé par Kaamo
    Enfin, tu utilises l'héritage "pseudo classique" pour créer tes objets. J'opterais plutôt pour l'héritage orienté prototype.
    J'ai réécris mes quelques lignes de code comme tu l'as proposé, mais je n'ai pour le moment pas compris l'intérêt. Fondamentalement les 2 manières passent par prototype. Pourquoi préfères-tu cette manière de travailler ?

    Citation Envoyé par fredoche
    Il me semble que Gregco pose bien le problème à la base en évoquant le notion de tiers, par le biais de script externe.
    C'est ça. J'ai conscience que le code est en claire et que le client lui même a plein pouvoir sur l’exécution de mon code JS. Par contre, je souhaite qu'un script tier ne puisse pas altérer les variables ou méthodes des mes objets. Kaamo m'a, semble-t-il, fournit la réponse à ma question (un grand merci Kaamo)... en tout cas, j'ai pas encore réussi à contourner sa solution.

    Citation Envoyé par fredoche
    la sécurité existe avec javascript, c'est un élément de la chaîne de sécurité comme un autre
    C'est ainsi que je perçois la couche javascript, un élément faisant partit d'un tout. J'ai évidement conscience de l'importance des contrôles côtés serveurs.
    Un grand merci fredoche pour les liens que tu m'as donnés. Je me pencherais sur Caja et adsafe.

    Citation Envoyé par SylvainPV
    ... penser en termes de classes dans un langage de programmation orientée prototype est une erreur.
    Je comprend. J'espère que tu ne m'en voudras pas de continuer à utiliser le vocabulaire propre à la POO... pour me faire comprendre c'est plus facile. (exemple : multi-héritage )

    En tout cas un grand merci pour vos nombreuses participations. C'est très enrichissant.

    Cordialement,
    Greg

  14. #14
    Rédacteur

    Avatar de danielhagnoul
    Homme Profil pro
    Étudiant perpétuel
    Inscrit en
    Février 2009
    Messages
    6 389
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 73
    Localisation : Belgique

    Informations professionnelles :
    Activité : Étudiant perpétuel
    Secteur : Enseignement

    Informations forums :
    Inscription : Février 2009
    Messages : 6 389
    Points : 22 933
    Points
    22 933
    Billets dans le blog
    125
    Par défaut
    Optimisation ? Restreindre l'accès au code ? Exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    var game = ( function(){
     
    	var caracteristiques = function caracteristiques(){
    			this.attaque = 0;
    			this.defense = 0;
    		},
    		animal = function animal( nom ){
    			this.nom = nom;
    			this.niveau = 1;
    			this.caracteristiques = new caracteristiques();
    		},
    		animalOurs = function animalOurs( nom ){
    			animal.call( this, nom ? nom : "Ours" );
    			this.caracteristiques.setDefense( 3 );
    		},
    		animalLoup = function animalLoup( nom ){
    			animal.call( this, nom ? nom : "Loup" );
    			this.caracteristiques.setDefense( 1 );
    		},
    		humain = function humain( nom, prenom ){
    			this.nom = nom;
    			this.prenom = prenom;
    			this.caracteristiques = new caracteristiques();
    			this.animauxInvoques=[]; 
    		},
    		game = function game(){
    			var gameName = "Game name",
    				humain1 = new humain( "Smith", "John" ),
    				humain2 = new humain( "Hollande", "Angella" ),
    				newAnimal = null;
     
    			humain1.caracteristiques.setAttaque( 2 );
     
    			newAnimal = new animalOurs();
    			newAnimal.caracteristiques.setAttaque( 5 );
    			humain2.animauxInvoques.push( newAnimal );
     
    			newAnimal = new animalLoup();
    			newAnimal.caracteristiques.setAttaque( 1 );
    			humain2.animauxInvoques.push( newAnimal );
     
    			// debug, console touche F12
    			console.log( humain1, humain2 );
    		};
     
    	caracteristiques.prototype.setAttaque = function setAttaque( attaque ){
    		this.attaque = attaque;
    	};
     
    	caracteristiques.prototype.setDefense = function setDefense( defense ){
    		this.defense = defense;
    	};
     
    	animal.prototype.toString = function toString(){
    		return( this.nom );
    	};
     
    	animalOurs.prototype = Object.create( animal.prototype );
    	animalLoup.prototype = Object.create( animal.prototype );
     
    	return new game();
    })();

  15. #15
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    Citation Envoyé par Gregco Voir le message
    Je comprend. J'espère que tu ne m'en voudras pas de continuer à utiliser le vocabulaire propre à la POO... pour me faire comprendre c'est plus facile. (exemple : multi-héritage )
    Non, je ne t'en veux pas bien sûr, mais tu devrais creuser la question. Les classes et les prototypes sont deux paradigmes différents, mais tous les deux de la programmation orientée objet. A lire : http://fr.wikipedia.org/wiki/Program...e_et_prototype

    Une vieille querelle vient de certains codeurs Java et C# qui ne veulent pas reconnaître qu'on puisse faire de la programmation orientée objet en JavaScript sous prétexte qu'il n'y a pas de classes. C'est assez agaçant de voir des développeurs coincés sur l'unique façon dont ils appris la POO. Enfin je ne veux pas soulever de nouveaux débats inutiles.

  16. #16
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    J'ai réécris mes quelques lignes de code comme tu l'as proposé, mais je n'ai pour le moment pas compris l'intérêt. Fondamentalement les 2 manières passent par prototype. Pourquoi préfères-tu cette manière de travailler ?
    Justement, il ne faut pas coder comme on le préfère, mais comme il est plus judicieux de le faire, en fonction du langage. Quand je fais du Java, je ne vais pas coder en pensant POO prototype. Pourquoi devrais je donc penser POO classique en JavaScript si le langage a été pensé autrement ? (bien que je préfère quand même la puissance et la souplesse de la POO prototype )

    Oui, les deux pattern "passent par prototype". Mais il y a quand même une nuance énorme. L'un est connu comme le pattern constructor de l'héritage par prototype. L'autre est le pattern prototype de l'héritage par prototype.

    A cause de l'influence de Java à l'époque, le mot clé new était très en vogue et a été amené dans JavaScript, dommage. L'erreur, qui apporte beaucoup de confusion, a été d'utiliser les function comme constructeur d'objet en plus de l'utilisation "classique" qui est de faire une suite de traitement et de renvoyer un résultat.

    Je pense que tu confonds la propriété prototype (attachée d'office aux objets créés via new Function ou par sa forme littérale function [toto](){}), du prototype de chaque objet (instance) qui permet de lier un objet "fils" à un objet "père".

    L'héritage pseudo classique (ou le pattern constructor de l'héritage par prototype) emploie le mot clé new suivi de Truc() (qui est un objet Function). Cet objet contient donc par défaut la propriété prototype qui va contenir toutes les méthodes/attributs "mères" de l'instance que l'on veut créer. Truc contient également par défaut la propriété prototype.constructor qui contient les directives à réaliser à l'emploie de new.
    Truc a également un prototype (comprendre un père), comme tout objet. En l'occurrence, le prototype de Truc est Function
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    function Truc() {
      /* Ceci sera contenu dans la propriété Truc.prototype.constructor */
      this.nom = 'Eich';
      this.prenom = 'Brendan';
    }
     
    /* Ceci sera contenu dans la propriété Truc.prototype */
    Truc.prototype.method1 = function () {
      console.log('Je suis la méthode 1');
    };
    Truc.prototype.method2 = function () {
      console.log('Je suis la méthode 2');
    };
     
    /* Tu préféreras d'ailleurs cette forme équivalente histoire de mutualiser un peu */
    Truc.prototype = {
      method1: function () {
        console.log('Je suis la méthode 1');
      },
      method2: function () {
        console.log('Je suis la méthode 2');
      }
    }
     
    /* Je créée une instance truc1, créée à partir de Truc */
    var truc1 = new Truc();
    Si on décortique truc1 :
    Il contient deux propriétés par défaut, telles définies dans le constructor :
    - nom: "Eich"
    - prenom: "Brendan"
    Il contient un prototype, comprendre un papa, qui contient donc toutes les propiétés/méthodes définies préalablement dans la propriété prototype de Truc :
    - method1
    - method2

    Là on cela est dangereux, c'est si tu oublies new. En l'oubliant, prototype.constructor ne sera pas appelé et this ne "pointera" pas sur ton instance mais sur l'objet global window.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    /* A NE PAS FAIRE */
    var truc1 = Truc();
    Ici, tu appelles une fonction en tant que telle, et non plus un constructeur d'instance. Une fonction, par définition (sans être appelée par new), retourne toujours une valeur. Si une valeur n'est pas explicitement retournée (à l'aide de return), undefined est retournée. C'est ce qui se passe dans ce cas, undefined est retourné et stocké dans truc1. Quant à Truc(), il place nom et prenom dans this (window).
    C'est donc le gros danger : confondre les fonctions "classiques" des fonctions faisant office de constructeur.

    L'héritage par prototype (ou le pattern prototype de l'héritage par prototype) utilise Object.create. Il n'y a plus de notion de new ou de this, et là est toute la différence. On dit aussi que c'est de l'héritage par délégation. Je te renvoie sur mon lien ci dessus pour des exemples. On ne manipule que des objets, il n'y a plus de bidouille avec Function et ses propriétés qui portent à confusion.

    Pour troller un peu (), voici pourquoi je préfère l'héritage par prototype à l'héritage classique :

    Classique :
    - classes immuables, on ne peut pas les modifier au runtime
    - l'héritage multiple est compliqué
    - c'est verbeux à souhait entre les interfaces, les classes abstraites etc

    Prototype :
    - C'est flexible, malléable, mutable
    - multiple prototype
    - tu manipules que des objets, tu les étends, c'est simple

  17. #17
    Rédacteur/Modérateur

    Avatar de SylvainPV
    Profil pro
    Inscrit en
    Novembre 2012
    Messages
    3 375
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2012
    Messages : 3 375
    Points : 9 944
    Points
    9 944
    Par défaut
    On peut aussi étendre le prototype de Function pour se simplifier la vie. Par exemple :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    Function.prototype.faireClasseEnfant = function( constructeurEnfant ){
        constructeurEnfant.prototype = new this;
        constructeurEnfant.prototype.constructor = constructeurEnfant;
        constructeurEnfant.prototype.parent = this.prototype;
        return constructeurEnfant;
    }
     
    var Animal = function(){
        this.alive = true;
        this.cri = "roar!";
    };
    Animal.prototype.crier = function(){
        if(this.alive){ alert(this.cri); }
    };
     
    var Cat = Animal.faireClasseEnfant( function(name){
        this.name=name;
        this.cri = 'miaou!';
    } );
     
    Cat.prototype.miaule=function(){
        this.parent.crier.call(this);
    };
    Cat.prototype.toString=function(){
        return '[Cat "'+this.name+'"]';
    };
     
    var felix = new Cat( "Felix" );
    alert(felix);
    felix.miaule();

  18. #18
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    J'étends les prototypes des objets natifs seulement si c'est une fonctionnalité pas encore présente mais spécifiée par la norme. (exemple : Object.create). Je pense que c'est mieux de passer par un objet qui fait ça, mais bon c'est un style après.
    Comme jouer avec this et new, j'évite de plus en plus et préfère un Object.create

  19. #19
    Membre du Club
    Inscrit en
    Juin 2003
    Messages
    71
    Détails du profil
    Informations forums :
    Inscription : Juin 2003
    Messages : 71
    Points : 54
    Points
    54
    Par défaut
    Citation Envoyé par Kaamo Voir le message
    Je pense que tu confonds la propriété prototype...
    Je pense que tu as mis le doigt sur le problème principal :-) Firebug m'avait conduit, à tord, à penser que le prototype (instance) était représenté par la propriété du même nom. Magistrale analyse ! Chapeau !

    Un grand merci pour cette explication limpide et détaillée de l'héritage pseudo classique et de l'héritage par prototype.

    L'exemple de Sylvain m'a bluffé. Je ne pensais pas que l'on pouvait aussi librement manipuler javascript. ça m'a effectivement ouvert les yeux sur cette logique "prototype" plutôt que POO.

    Il me reste une question à vous poser. On verra si j'ai bien tout compris.

    Dans mon code initial, à chaque nouvel Animal (AnimalLoup, AnimalOurs), un nouvel objet Caracteristiques est créé puis stocké dans la variable this.caracteristiques.

    Est-ce juste, en imaginant devoir créer 1 million d'Animaux, qu'il serait plus performant d'éviter la création de cet objet Caracteristiques en ayant une class Animal ainsi construite ? (AnimalOurs et AnimalLoup héritant du prototype d'Animal)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    var Animal = {
    	init: function(nom) {
    		this.nom = nom
    	},
    	niveau: 1,
    	attaque: 0,
    	defense: 0,
    	setAttaque: function(attaque) {
    		this.attaque = attaque;
    	},
    	setDefense: function(defense) {
    		this.defense = defense;
    	},
    	toString: function() {
    		return(this.nom);
    	}
    };
    Cordialement,
    Greg

  20. #20
    Membre émérite
    Avatar de Kaamo
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    1 165
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 1 165
    Points : 2 778
    Points
    2 778
    Par défaut
    ça dépend si c'est des caractéristiques partagées ? Ou des caractéristiques propres à chaque instance de chaque animal.

    Voici un exemple pour bien comprendre. Je me suis basé sur l'héritage par prototype (pattern proto et non pattern constructor comme Sylvain) :

    J'ai un peu commenté, tu peux poser des questions si tu ne comprends pas certains passages.
    Code javascript : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    /* Prototype Animal */
    var Animal = {
      init: function(nom, caracsPerso, niveau) {
        this.nom = nom || 'Inconnu'; // si nom n'est pas renseigné : 'Inconnu' par défaut
        this.niveau = niveau || 1; // si niveau n'est pas renseigné : 1 par défaut
        this.caracs = caracsPerso || this.caracDefault;
      },
      caracDefault: {attaque: 0, defense: 0},
      setAttaque: function(attaque) {
        /* code pour changer la carac */
      },
      setDefense: function(defense) {
        /* code pour changer la carac */
      },
      toString: function() {
        return('['+ this.nom + ' Animal]');
      }
    };
     
    /* Prototype Ours */
    var Ours = Object.create(Animal);
    Ours.toString = function() {
      return('['+ this.nom + ' Ours]');
    }
    Ours.caracDefault = {attaque: 0, defense: 1};
     
    /* Prototype Loup */
    var Loup = Object.create(Animal);
    Loup.toString = function() {
      return('['+ this.nom + ' Loup]');
    }
    Loup.caracDefault = {attaque: 1, defense: 0};
     
    /* Création des instances */
    ours1 = Object.create(Ours);
    ours1.init('Baloo');
     
    loup1 = Object.create(Loup);
    loup1.init('Croc blanc', {attaque: 5, defense: 5});
     
    loup2 = Object.create(Loup);
    loup2.init('Ptit loup');
     
    console.log(ours1);
    console.log(loup1);
    console.log(loup2);
    Avec ce pattern, il faut systématiquement appeler init pour chaque instance.
    Tout ce qui est dans init sera copié dans l'instance car ce sont des caractéristiques propres à chaque instance d'animal.
    Chaque instance pointe vers un __proto__ (Parent) (Loup ou Ours)
    Loup et Ours pointent eux même vers un __proto__ (Animal).
    Animal, enfin, pointe sur le __proto__ de base JavaScript : ObjectC'est ce qu'on appelle la chaîne de prototype.
    Si tu demandes une propriété, JavaScript va regarder dans l'objet (ours1) s'il la trouve. S'il ne la trouve pas, il va checker dans le proto, puis le proto suivant, etc, jusqu'à la fin. S'il ne trouve rien, il renvoie undefined.

    Ce qui donne, pour mon instance ours1 : ours1 > Ours > Animal > Object

    Imagine que tu veuilles la propriété caracDefault.
    JS check dans ours1 : pas trouvé.
    JS check dans le proto Ours : on renvoie car c'est présent.
    (sinon, il aurait renvoyé celle d'Animal)



    En terme de mémoire, tu auras donc un seul objet Ours, un seul objet Loup, un seul objet Animal. Et autant d'instance que tu souhaites qui pointeront vers les objets cités ci avant

Discussions similaires

  1. Réponses: 13
    Dernier message: 11/07/2011, 05h17
  2. Réponses: 1
    Dernier message: 16/12/2006, 00h27
  3. [POO Optimisation] Règles d'écriture d'un site PHP
    Par KiLVaiDeN dans le forum Langage
    Réponses: 19
    Dernier message: 30/09/2006, 01h08
  4. [Sécurité] Conseils sécurité et optimisation
    Par cyrill.gremaud dans le forum Langage
    Réponses: 2
    Dernier message: 19/06/2006, 23h51
  5. Réponses: 6
    Dernier message: 28/07/2005, 21h14

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo