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 :

Prototypes et Itérations


Sujet :

JavaScript

  1. #1
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut Prototypes et Itérations
    Bonjour à tous.

    Quelqu'un saurait-il m'expliquer pourquoi l'ajout de méthodes à un objet rends cette méthode visible lors de l'itération for ?

    Exemple:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    Array.prototype.min = function () {
    	var min;
    	for (i in this) {
    		write(this[i]);
    		if (min == undefined || min > this[i])
    			min = this[i];
    	}
    	return min;
    }
     
    write([1,2,3].min());
    Le problème c'est que j'ai besoin d'ajouter des fonctionnalités à des objets natifs mais cela à tendance à perturber jQuery (surtout quand on ajoute des méthodes à Object, c'est la cata).

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 128
    Points : 210
    Points
    210
    Par défaut
    Cela est du au mécanisme d'héritage en javascript. Lorqu'une propriété ne peut être résolue le runtime va chercher de manière récursive dans la chaine de prototypage.

    De la même manière lors d'une itération sur les clés tu itère sur les clés de l'objet (instances) mais aussi sur les clés visibles dans ta chaine de prototypage.

    Pour itérer sur un objet sans itérer les clés héritées il faut faire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(var i on obj) if (obj.hasOwnProperty(i)){
        // loop
    }
    De plus tu ne dois pas itérer un tableau par clés, mais par indexs, sinon tu traversera aussi des propriétés de l'instance comme length (ce que tu ne veux pas faire) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    for(var i = 0, n = arr.length; i<n; i++){
        // loop
    }
    PS : il est considéré comme une mauvaise pratique d'augmenter les objets natifs. Il y a toujours une meilleure solution que d'ouvrir cette boîte de Pandore.

  3. #3
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Effectivement, c'est dangereux d'ajouter des prototypes à tous les Objets et jQuery a parfois un peu du mal avec ça.

    essaye de faire des trucs du genre :

    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
     
    // nouvelle classe MyObject avec héritage(extend) basique
    function MyObject(h) {
        if (h) this.extend(h);
        return this;
    }
    MyObject.prototype.extend = function (o) {
        for (var i in o)
            this[i] = o[i];
        return this;
    };
     
    // déclaration de prototypes personalisés
    MyObject.prototype.toArray = function () {
        var r = [];
        for (var i in this)
            if (typeof (this[i]) != 'function' && typeof (this[i]) != 'object') r.push(this[i]);
        return r;
    }
     
    // création d'un nouvel objet "myObject" à partir d'un objet et utilisation de méthode prototypée
    var obj = new MyObject({
        name: 'john',
        age: 22
    });
    alert(obj.toArray());
     
     
    //--------------------------------------------------------
    // après tu peux facilement faire des nouvelles classes à partir de myObject :
    //--------------------------------------------------------
     
    // nouvelle classe personalisée
    function human(h) {
        return (new MyObject(h)).extend(this);
    }
    human.prototype.sing = function () {
        alert('lalala');
    };
     
    // utilisation
    var me;
    me = new human({
        eyes: 'blues',
        height: '1m80'
    });
    me = me.extend({
        hair: 'red'
    });
    me.sing();
    alert(me.toArray());
    edit: indentation

  4. #4
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Merci @TheGwy. Ce que je ne comprenais pas c'est pourquoi les membre natifs des objets ne se retrouvent pas dans la liste des clés. Pourtant cela fait effectivement partie de leur prototype. Dois-je en déduire que c'est la VM qui "masque" ces clés ?

    PS : il est considéré comme une mauvaise pratique d'augmenter les objets natifs. Il y a toujours une meilleure solution que d'ouvrir cette boîte de Pandore.
    C'est noté. En revanche c'est une alternative séduisante pour palier les insuffisances du langage au niveau fonctionnel (c'est vrai quoi, y'a même pas trim sur les chaines )
    Vu qu'on ne devrait pas les augmenter, peut-on au moins en hériter ?

  5. #5
    Rédacteur

    Avatar de Bovino
    Homme Profil pro
    Développeur Web
    Inscrit en
    Juin 2008
    Messages
    23 647
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Gironde (Aquitaine)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 23 647
    Points : 91 220
    Points
    91 220
    Billets dans le blog
    20
    Par défaut
    Citation Envoyé par Benjamin Delespierre
    c'est vrai quoi, y'a même pas trim sur les chaines
    Heu... si : Le "core" JavaScript s'enrichit de nouvelles méthodes.

  6. #6
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 128
    Points : 210
    Points
    210
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    Merci @TheGwy. Ce que je ne comprenais pas c'est pourquoi les membre natifs des objets ne se retrouvent pas dans la liste des clés. Pourtant cela fait effectivement partie de leur prototype. Dois-je en déduire que c'est la VM qui "masque" ces clés ?
    Exactement, il y a une propriété interne DontEnum qui n'est pas accessible au code client.
    https://developer.mozilla.org/en/ECM...Enum_attribute
    Les nouvelles API ES5 permettent d'avoir accès à cette propriété, mais d'ici la que ce soit utilisable partout, tu as le temps de venir voir.

    Citation Envoyé par Benjamin Delespierre Voir le message
    C'est noté. En revanche c'est une alternative séduisante pour palier les insuffisances du langage au niveau fonctionnel (c'est vrai quoi, y'a même pas trim sur les chaines )
    Vu qu'on ne devrait pas les augmenter, peut-on au moins en hériter ?
    Oui, comme Willpower l'a montré tu peux parfaitement faire un Objet qui hérite ou encapsule un objet natif, et étendre celui-ci de manière sûre.

    Personnellement je suis plutôt adepte de l'objet avec des fonctions utilitaires statiques (genre StringUtils, etc). C'est un peu plus "lourd" syntaxiquement mais très clair niveau compréhension.

    Après si c'est un projet de petite ampleur où tu es l'auteur de tout le code (pas de passif, source externes, mashups, librairies, plugins) tu peux te permettre d'étendre les objets natifs car tu ne risque pas de casser du code qui n'est pas le tiens. Mais c'est quand même rare de se retrouver dans ce cas.

    Un bon article sur la question avec plusieurs approches décortiquées :
    http://perfectionkills.com/extending...s-evil-or-not/

  7. #7
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Oui, comme Willpower l'a montré tu peux parfaitement faire un Objet qui hérite ou encapsule un objet natif, et étendre celui-ci de manière sûre.
    Encapsuler ça va, mais pour l'héritage je galère comme un veau...

    J'ai tenté ça mais visiblement il manque quelque chose:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    myString.prototype = new String;
    myString.prototype.constructor = myString;
     
    function myString ( str ) {
    	String.call(this, str);
    }
     
    var str = new myString('test');
     
    dump(str instanceof String); // true
     
    write(str); // TypeError: String.prototype.valueOf called on incompatible Object

  8. #8
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    le problème c'est qu'en javascript, il y a grosso-modo 2 types de variables, les objets et les valeurs.

    le string étant ce j'appelle une variable de type valeur.

    tu ne pourras donc jamais faire de "write(myString)" en espérant afficher la valeur de ton String car ton "myString" sera un objet avec des champs et des méthodes.


    tu devras choisir soit à redéfinir toutes les méthodes de ton nouvelle objet "myString" du genre "myString.write()" soit rédéfinir le prototype de la classe String de base(native), ce qui est clairement mieux dans ce cas.

    en fait, pour les variables de type "valeur"(string, number, etc...) tu as intêret à jouer avec les prototypes.

    tandis que pour les objets, tu as intêret à créer une nouvelle classe encapsulante. (les array, étant un type d'objet particulier, c'est plus génant.).

    sinon comme le suggère theGwy, l'utilisation de fonctions utilitaires statiques sera encore le plus simple dans bien des cas.

  9. #9
    Membre actif
    Profil pro
    Inscrit en
    Décembre 2007
    Messages
    128
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Décembre 2007
    Messages : 128
    Points : 210
    Points
    210
    Par défaut
    En fait c'est un peu plus vicieux que cela.

    Il y a une subtilité en javascript les types littéraux peuvent avoir des méthodes car ils sont autoboxés.

    Quand tu fais par exemple "string".trim()
    le runtime va :
    - convertir ta string littérale en objet String,
    - executer String.trim
    - reconvertir l'objet en valeur littérale

    C'est visible parfois quand tu essaie d'attribuer une propriété à une valeur littérale : l'objet est autoboxé, ta propriété est écrite sans lever d'erreur, puis reconvertit en littéral ce qui te fait perdre ta propriété.

    Je pense que ton problème ici doit plus ou moins être en rapport avec ça (sous firebug ton code déclenche une récursion infinie).
    Mais en toute honnêteté je n'ai pas trop gratté.

    Si tu veux plus d'infos sur ce comportement tu devrais trouver ça sur le net, mais je sais (pour l'avoir lu) que "Javascript patterns" de stoyan stefanov consacre un chapitre la dessus où il explique tout de manière très claire.

  10. #10
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    En effet, je viens de lire un article intéressant sur l'autoboxing de JavaScript (ça m'a rappelé les wrappeurs en Java).

    Il semblerait donc que les objets natifs soient impossible à hériter en totalité car je n'arrive pas à redéfinir correctement .valueOf (on peut toujours passer par Object mais du coup, on ne réccupère jamais la chaine - on a [object Object]).

    Bref, j'ai finalement trouvé un moyen en utilisant une composition:
    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
    myString.prototype = new String;
     
    function myString ( s ) {
    	this.str = s;
    	for (var i = 0, l = s.length; i < l; i++) {
    		this[i] = s[i];
    	}
    }
     
    myString.prototype.toString = function () {
    	return this.str;
    }
     
    myString.prototype.valueOf = function () {
    	return String.valueOf.call(this.str);
    }
     
    myString.prototype.getLength = function () {
    	return this.str.length;
    }
     
    var str = new myString('test');
     
    dump(str instanceof String); // boolean true
    dump(str.charAt(3));         // string "t" (length=1)
    dump(str.length);            // number 0
    dump(str.getLength());       // number 4
    dump(str[2]);                // string "s" (length=1)
     
    write( str );                // test
    Comme vous l'avez constaté, les méthodes sont correctement hérités au prix d'un passage systématique par toString, on a bien le bon type (la classe mère est effectivement String) mais on n'a pas les propriétés dynamiques et on doit passer par des méthodes pour obtenir ce que l'on veut.

    Pour ceux que ça intéresse, voici le thread de Stack Overflow qui m'a mis sur la voie:http://stackoverflow.com/questions/6...ecially-string

    Edit: y'avait une erreur dans mon code.

  11. #11
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Ca ne marche que pour la classe "string" car en fait il y a conversion implicite de type (je pense) en string et que tu as surchargé la méthode toString.

  12. #12
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Je pense également. Mais c'est pas moi l'expert ici

    Le problème n'a pas l'air de se poser pour d'autres type, c'est assez étrange je dois dire...
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    myArray.prototype = new Array;
     
    function myArray () {
    	for (var i=0; i<arguments.length; i++)
    		this.push(arguments[i]);
    }
     
    var arr = new myArray(1,2,3);
     
    dump(arr instanceof Array); // boolean true
    dump(arr[0]);               // number 1
    dump(arr.length);           // number 3

  13. #13
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    pas bête l'utilisation de push pour convertir le this en array.

    par contre tu reviens au problème initial du sujet, ton "myArray" affichera un attribut length lors du parcours for(i in myArray) alors que ce length n'apparait pas lors d'un parcours d'array for(i in array) (edit: je n'ai rien dis, jQuery utilisera la classe array et toi la classe myArray, donc plus de pertubation lors de parcours d'array. ton problème semble donc résolu. je devrais faire plus attention au sujet de départ. )

    autrement, pour le fun, j'ai supprimé ta boucle de création(même si au final le code native qui la substitue doit sans doute en faire une lui aussi).

    et j'ai rajouté la méthode toString car (en tout cas sous chrome) un alert(myArray) provoquait une exception disant que Array.prototype.toString n'était pas générique.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function myArray(){
    	this.push.apply(this,arguments);
    }
    myArray.prototype = new Array();
    myArray.prototype.toString = function(){
    	return this.slice().toString();
    };

  14. #14
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Bien joué, merci.

    Apparement l'usage de Array.prototype.toString ne pose aucun problème dans le contexte de myArray:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    function myArray(){
    	this.push.apply(this,arguments);
    }
     
    myArray.prototype = new Array();
     
    myArray.prototype.toString = function(){
    	return Array.prototype.toString.call(this);
    };
     
    var arr = new myArray(1,2,3);
     
    write(arr);
    Tant qu'a faire, je préfère utiliser la méthode parente, ai-je raison ?

  15. #15
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    quand j'utilise ton code sous chrome :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function myArray(){
    	this.push.apply(this,arguments);
    }
    myArray.prototype = new Array();
    myArray.prototype.toString = function(){
    	return Array.prototype.toString.call(this);
    };
    avec simplement ceci :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    var a = new myArray(1,2,3);
    alert(a);

    j'ai une exception :

    Uncaught TypeError: Array.prototype.toString is not generic
    tandis qu'avec ma version de toString, ça semble fonctionner sous les 3 navigateurs les plus courants.



    edit: explications de ma version return this.slice().toString(); : en gros la méthode slice découpe un sous-array dans ton array à partir de la position arguments[0], sans argument ça découpe par défaut depuis la position 0, donc un sous-array commençant au début(jusqu'à la fin) donc ton array. (mais de type array et non myArray), donc myArrayObject.slice().toString(), renverra une conversion de myArray en array et appliquera le toString natif du array.

  16. #16
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    en mode un peu barbare :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    function myArray(){
    	[].push.apply(this,arguments);
    }
    myArray.prototype = [];
    myArray.prototype.toString = function(){
    	return this.slice()+'';
    };
    et en mode ultra compacte :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ((myArray=function(){[].push.apply(this,arguments)}).prototype=[]).toString=function(){return this.slice()+''};

  17. #17
    Expert éminent
    Avatar de Benjamin Delespierre
    Profil pro
    Développeur Web
    Inscrit en
    Février 2010
    Messages
    3 929
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Février 2010
    Messages : 3 929
    Points : 7 762
    Points
    7 762
    Par défaut
    Je vois... C'est étrange car les instances de myArray sont bien des Array (instanceof renvoie true). Donc je n'arrive pas à comprendre d'où vient cette erreur de "généricité"...

    Qu'on soit bien d'accord, c'est pas quelque chose qui me gène de redéfinir toString sans même appeller la méthode de la classe mère. Je me pose juste la question; comment fonctionne l'héritage de types natifs en JS.

    J'ai encore deux-trois articles à lire sur la question, j'espère y trouver des réponses.

  18. #18
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    Citation Envoyé par Benjamin Delespierre Voir le message
    Je vois... C'est étrange car les instances de myArray sont bien des Array (instanceof renvoie true). Donc je n'arrive pas à comprendre d'où vient cette erreur de "généricité"...

    Qu'on soit bien d'accord, c'est pas quelque chose qui me gène de redéfinir toString sans même appeller la méthode de la classe mère. Je me pose juste la question; comment fonctionne l'héritage de types natifs en JS.

    J'ai encore deux-trois articles à lire sur la question, j'espère y trouver des réponses.
    en fait, en javascript il n'y a pas d'héritage de classe à proprement parler mais juste de prototype.

    ton objet reste un objet de type myArray mais ne devient jamais réellement un objet de type array. même s'il "hérite" de ses méthodes via son prototypage et que "instanceof" renvoie vrai car la signature de l'array sera accesible depuis ton objet via le prototype qu'il a hérité.

    apparement la création de ton objet via la méthode "push" le rend encore un peu plus array en lui ajoutant par exemple un attribut length et fait que la majorité des méthodes héritées via le prototype d'array(slice, concat, etc..) acceptent de s'exécuter sur ton objet malgré qu'il ne soit pas réellement un array natif.

    par contre il n'arrive pas à appliquer la méthode toString(de array) sur ton objet qui de base est un "object object". d'ailleurs si dans ta méthode myArray.prototype.toString tu fais : return Object.prototype.toString.call(this); il ne renverra pas d'erreur. Mais ce ne sera pas le toString que tu attends car il affichera "[Object Object]" au lieu de par exemple "[1,2,3]". c'est pour quoi, dans ma méthode toString, je converti d'abord l'objet myArray en vrai array avant de lui appliquer le toString d'array.

    de même, tu aurais intêret à tester toutes les méthodes du prototype d'array car il en existe p-ê d'autres qui refusent de s'appliquer sur ton objet qui n'est pas réellement un array.

    enfin, je ne suis pas expert, mais il me semble que mes explications sont les bonnes.

  19. #19
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    après des rapides test sur un objet de type myArray. toutes les méthodes semblent bien fonctionner.

    il y a juste l'attribut "constructor" qui fait référence à Array au lieu de myArray.

    tu peux le corriger comme ceci :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myArray.prototype.constructor = myArray; // à placer après la surcharge du prototype par le new Array();
    mais ça ne sert un peu à rien. personne n'utilise l'attribut constructor.

    enfin, la méthode concat, qui renvoie un array et non un myArray.

    exemple :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    objectMyArray.concat(objectMyArray); // renvoie un nouvel array et non un myArray
    tu peux donc redéfinir concat comme suit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    myArray.prototype.concat = function(){
    	var myArr = new myArray(); // create new myArray
    	var arr = [].concat.apply(this,arguments); // create new array with concat this and arguments
    	myArr.push.apply(myArr,arr); // push array's data in myArray
    	return myArr; // return myArray
    };
    bien que ce serait plus propre de définir un constructeur de myArray prenant un array en paramètre.

    il suffirait alors de faire (pour concat) un truc du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    myArray.prototype.concat = function(){
    	// /!\ S'IL EXISTE UN CONSTRUCTOR PRENANT UN ARRAY /!\
    	return new myArray( [].concat.apply(this,arguments) ); 
    };

  20. #20
    Membre expérimenté Avatar de Willpower
    Homme Profil pro
    sans emploi
    Inscrit en
    Décembre 2010
    Messages
    1 009
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : sans emploi

    Informations forums :
    Inscription : Décembre 2010
    Messages : 1 009
    Points : 1 519
    Points
    1 519
    Par défaut
    en résumé, complété et commenté :

    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
    // constructor par défaut prenant des éléments
    // exemple d'utilisation :
    // var myArr = new myArray(1,2,3);
    function myArray(){
    	this.push.apply(this,arguments);
    }
     
    // ajout des méthodes de array en écrassant le prototype (~héritage)
    myArray.prototype = new Array();
     
    // [INUTILE] correction de l'attribut "constructor" (qui a été écrasé à la ligne au dessus)
    myArray.prototype.constructor = myArray;
     
    // création d'une méthode "toArray"
    myArray.prototype.toArray = function(){
    	return this.slice();
    };
     
    // correction de la méthode "toString" (qui plantait sous certains navigateurs comme chrome)
    myArray.prototype.toString = function(){
    	return this.toArray().toString();
    };
     
    // ajout d'un "init" qui ajoute les éléments d'un array à l'objet courant
    // exemple d'utilisation : 
    // var myArr = (new myArray()).init([1,2,3]);
    myArray.prototype.init = function(array){
    	this.push.apply(this,array);
    	return this;
    };
     
    // correction de la méthode "concat" (qui renvoyait un array au lieu d'un myArray)
    myArray.prototype.concat = function(){
    	var a = [].map.call(arguments,function(e){return e.toArray?e.toArray():e;});
    	return (new myArray()).init(a.concat.apply(this.toArray(),a));
    };

    exemple d'utilisation :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    var dump = dump || function(e){
    	document.write(e,'<br/>');
    }
     
    var a = new myArray(1,2,3);
    var b = a.concat([4,5,6],[7,8,9,0],a);
     
    for(var i in b)
    	dump(i+" : "+b[i]);
    dump('---');
    for(var i in a)
    	dump(i+" : "+a[i]);

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. [Prototype] Je ne comprends pas
    Par SpaceFrog dans le forum Bibliothèques & Frameworks
    Réponses: 30
    Dernier message: 15/12/2005, 10h59
  2. Réponses: 6
    Dernier message: 20/11/2005, 02h53
  3. [ JSP ] Itération en JSP
    Par samios dans le forum Servlets/JSP
    Réponses: 7
    Dernier message: 22/10/2005, 18h15
  4. [Système] Récursivité et itération
    Par Floréal dans le forum Langage
    Réponses: 8
    Dernier message: 19/04/2005, 14h57
  5. Récupérer le prototype d'une fonction
    Par uaz dans le forum Général Python
    Réponses: 2
    Dernier message: 27/07/2004, 17h24

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