Précédent   Forum des professionnels en informatique > Webmasters - Développement Web > JavaScript
JavaScript Forum programmation JavaScript. Lire : Cours JavaScript, FAQ JavaScript, Toutes les FAQ JavaScript et Sources JavaScript
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse Proposer ce sujet en actualité
 
Outils de la discussion
Publicité
'
Vieux 21/11/2011, 16h23   #1
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
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 :
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).
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 16h36   #2
Membre régulier
 
Inscription : décembre 2007
Messages : 61
Détails du profil
Informations forums :
Inscription : décembre 2007
Messages : 61
Points : 83
Points : 83
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 :
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 :
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.
TheGwy est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 21/11/2011, 16h54   #3
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
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 :
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
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 21/11/2011, 17h18   #4
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
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 ?

Citation:
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 ?
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 17h25   #5
Responsable Développement Web

 
Avatar de Bovino
 
Homme Didier Mouronval
Développeur Web
Inscription : juin 2008
Messages : 13 807
Détails du profil
Informations personnelles :
Nom : Homme Didier Mouronval
Âge : 41
Localisation : France, Gironde (Aquitaine)

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

Informations forums :
Inscription : juin 2008
Messages : 13 807
Points : 35 789
Points : 35 789
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.
__________________
Pas de question technique par MP !
Tout le monde peut participer à developpez.com, vous avez une idée, contactez-moi !
Vous possédez un blog et aimeriez diffuser vos billets sur le forum, contactez-moi !
Mes formations video2brain : La formation complète sur JavaScriptJavaScript et le DOM par la pratiquePHP 5 et MySQL : les fondamentaux
Mon livre sur jQuery
Bovino est actuellement connecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 17h30   #6
Membre régulier
 
Inscription : décembre 2007
Messages : 61
Détails du profil
Informations forums :
Inscription : décembre 2007
Messages : 61
Points : 83
Points : 83
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/
TheGwy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 17h41   #7
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
Citation:
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 :
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
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 17h52   #8
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
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.
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 18h05   #9
Membre régulier
 
Inscription : décembre 2007
Messages : 61
Détails du profil
Informations forums :
Inscription : décembre 2007
Messages : 61
Points : 83
Points : 83
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.
TheGwy est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 18h30   #10
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
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 :
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.
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 18h40   #11
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
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.
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 21/11/2011, 18h47   #12
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
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 :
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
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 11h11   #13
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
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 :
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();
};
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 22/11/2011, 11h49   #14
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
Bien joué, merci.

Apparement l'usage de Array.prototype.toString ne pose aucun problème dans le contexte de myArray:
Code :
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 ?
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 11h54   #15
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
quand j'utilise ton code sous chrome :

Code :
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 :
1
2
var a = new myArray(1,2,3);
alert(a);

j'ai une exception :

Citation:
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.
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 12h07   #16
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
en mode un peu barbare :

Code :
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 :
((myArray=function(){[].push.apply(this,arguments)}).prototype=[]).toString=function(){return this.slice()+''};
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 12h08   #17
Modérateur
 
Avatar de Benjamin Delespierre
 
Benjamin Delespierre
Développeur Web
Inscription : février 2010
Messages : 2 991
Détails du profil
Informations personnelles :
Nom : Benjamin Delespierre
Âge : 24
Localisation : France

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

Informations forums :
Inscription : février 2010
Messages : 2 991
Points : 5 032
Points : 5 032
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.
__________________
A la recherche d'un framework MVC facile a prendre en main ? Essayez Axiom
Nouveau: la référence d'Axiom est disponible sur GitHub (je la peaufine en ce moment même).

Un problème correctement identifié est à moitié résolu, évitez de poster l'intégralité de votre code avec pour seule explication "ça ne marche pas...".
Pour identifier correctement vos problèmes PHP, utilisez la gestion des erreurs et xdebug.

Les boutons et existent, servez-vous en
Benjamin Delespierre est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 12h22   #18
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
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.
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 12h59   #19
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
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 :
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 :
objectMyArray.concat(objectMyArray); // renvoie un nouvel array et non un myArray
tu peux donc redéfinir concat comme suit :

Code :
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 :
1
2
3
4
myArray.prototype.concat = function(){
	// /!\ S'IL EXISTE UN CONSTRUCTOR PRENANT UN ARRAY /!\
	return new myArray( [].concat.apply(this,arguments) ); 
};
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 22/11/2011, 13h12   #20
Membre Expert
 
Avatar de Willpower
 
Homme Boris Dessy
sans emploi
Inscription : décembre 2010
Messages : 871
Détails du profil
Informations personnelles :
Nom : Homme Boris Dessy
Localisation : Belgique

Informations professionnelles :
Activité : sans emploi

Informations forums :
Inscription : décembre 2010
Messages : 871
Points : 1 380
Points : 1 380
en résumé, complété et commenté :

Code :
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 :
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]);
Willpower est déconnecté   Envoyer un message privé Réponse avec citation 10
Réponse Proposer ce sujet en actualité Cette discussion est résolue.
Outils de la discussion



Fuseau horaire GMT +2. Il est actuellement 10h56.


 
 
 
 
Partenaires

Hébergement Web