Bonjour à tous,
Depuis quelques temps je me suis beaucoup intéressé à l'héritage par prototype en JS. Je m'en sors plutôt bien je trouve, mais aujourd'hui je suis confronté à un petit problème.
En effet, j'essaie de créer une classe "Collection" qui hérite de Array et qui permet de spécialisé celui-ci en spécifiant un type. Jusque là je n'ai aucun problème.
Celui-ci survient lorsque j'essaie en fin de compte de chaîner plusieurs fois la méthode "push" de ma collection. Celle-ci renvoie un objet undefined alors que je fais un "return this;" à la fin de celle-ci.
J'ai fait plusieurs console.log et tester un peu tous les états de "this" dans la méthode "push" et la valeur de celle-ci est toujours valide. Mais voilà, à la sortie de la fonction, je récupère toujours une valeur undefined.
Je vous remercie si vous pouviez m'éclairer un petit peu plus.
Je poste à la suite mon code ainsi qu'un JSFiddle. (le code est par ailleurs beaucoup simplifier par rapport à ma version de base qui contient d'autre éléments pour gérer des canvas).
Liens JSFiddle: http://jsfiddle.net/08azs78t/4/
Modifié par ChibiKookie (02 Sep 2014 - 13:51)
Depuis quelques temps je me suis beaucoup intéressé à l'héritage par prototype en JS. Je m'en sors plutôt bien je trouve, mais aujourd'hui je suis confronté à un petit problème.
En effet, j'essaie de créer une classe "Collection" qui hérite de Array et qui permet de spécialisé celui-ci en spécifiant un type. Jusque là je n'ai aucun problème.
Celui-ci survient lorsque j'essaie en fin de compte de chaîner plusieurs fois la méthode "push" de ma collection. Celle-ci renvoie un objet undefined alors que je fais un "return this;" à la fin de celle-ci.
J'ai fait plusieurs console.log et tester un peu tous les états de "this" dans la méthode "push" et la valeur de celle-ci est toujours valide. Mais voilà, à la sortie de la fonction, je récupère toujours une valeur undefined.
Je vous remercie si vous pouviez m'éclairer un petit peu plus.
Je poste à la suite mon code ainsi qu'un JSFiddle. (le code est par ailleurs beaucoup simplifier par rapport à ma version de base qui contient d'autre éléments pour gérer des canvas).
Liens JSFiddle: http://jsfiddle.net/08azs78t/4/
/**
* Kookie Namespace
*/
var kk, kookie;
;(function(window, document) {
'use strict';
// Definition of kk namespace
kk = {};
// Object Detection Enhancing
(function() {
var types = {}, toString = types.toString, hasOwn = types.hasOwnProperty;
/**
* Util namespace of kookie
*/
kk.util = {};
/**
* Iterates over an array and executing the callback passed for each iteration
* @param {Array} array The array iterated
* @param {Function} fn The callback to execute for each iteration
*/
kk.util.each = function(array, fn) {
for (var i = 0, l = array.length; i < l; ++i) {
fn(array[ i ], i, array);
}
};
/**
* Get the type of an object in a more accurate way than the basic "typeof" keyword
* @param {mixed} mixed The variable
* @return {string} The type of the mixed variable passed
*/
kk.util.getType = function(mixed) {
if (mixed === null)
return mixed +'';
return typeof mixed === 'object' || typeof mixed === 'function' ?
types[toString.call(mixed)] || 'object' :
typeof mixed;
};
// Feed types map/hash
kk.util.each('Boolean Number String Function Array Date RegExp Object Error'.split(' '), function(name) {
types['[object '+ name +']'] = name.toLowerCase();
});
})();
// Object Inheritance
(function() {
var slice = Array.prototype.slice, inherit, copyProto, mixin;
copyProto = function(klass, source, parent) {
for (var property in source) {
if (kk.util.getType(parent) !== 'null' &&
property in klass.prototype &&
typeof klass.prototype[ property ] === 'function' &&
typeof source[ property ] === 'function') {
var __super__ = parent.prototype;
klass.prototype[ property ] = (function(property, __super__) {
return function() {
var tmpSuper = this.__super__;
this.__super__ = (function(){
return function() {
var args = slice.call(arguments, 0);
var methodName = args[0] in __super__ ? args.shift() : property;
__super__[methodName].apply(this, args);
};
})();
source[ property ].apply(this, arguments);
(tmpSuper === undefined) ? delete this.__super__ : this.__super__ = tmpSuper;
};
})(property, __super__);
}
else {
klass.prototype[ property ] = source[ property ];
}
}
};
mixin = function(properties) {
for (var property in properties) {
this.prototype[ property ] = properties[ property ];
}
};
inherit = function() {
var parent = null,
abstract = false,
properties = slice.call(arguments, 0);
if (typeof properties[0] === 'function') {
parent = properties.shift();
}
if (typeof properties[0] === 'boolean') {
abstract = properties.shift();
}
// Create KKClass constructor
var KKClass = (function(abstractClass) {
return function KKClass() {
if (abstractClass === true) {
throw {
name:'Abstract Class Error',
message: 'Cannot instanciate an abstract class',
toString: function() {
return this.name +': '+ this.message;
}
};
}
else {
this.initialize.apply(this, arguments);
}
};
})(abstract);
// KKClass ultra functionnalities (like mixing protos)
KKClass.mixin = mixin;
var KKPrototype = function(){};
if (parent) {
KKPrototype.prototype = parent.prototype;
}
KKClass.prototype = new KKPrototype();
// Now, we're copying the new protot into the child class
for (var i = 0, l = properties.length; i < l; ++i) {
copyProto(KKClass, properties[ i ], parent);
}
// If no initialize method is present then create a default one
if (typeof KKClass.prototype.initialize === 'undefined') {
KKClass.prototype.initialize = function(){};
}
KKClass.prototype.constructor = KKClass;
return KKClass;
};
kk.util.createClass = inherit;
})();
// Collection
(function() {
var Collection, push = Array.prototype.push;
Collection = kk.util.createClass(Array, {
initialize: function(type) {
this.type = type;
},
push: function() {
for (var i = 0, l = arguments.length; i < l; ++i) {
if (!(arguments[ i ] instanceof this.type) && arguments[ i ] !== new this.type(arguments[ i ]).valueOf()) {
throw {
name: 'Collection Type Error',
message: 'Could not insert a value of "'+ typeof arguments[ i ] +'" on collection',
toString: function() {
return this.name +': '+ this.message;
}
}
}
else {
push.call(this, arguments[ i ]);
}
}
return this;
},
add: function() {
return this.push.apply(this, arguments);
},
getObjects: function(type) {
if (typeof type === 'undefined' || type == this.type) {
return this;
}
// If the specified type is another type than the collection type
// Then we create a new Collection from this type
var collection = new this.constructor(type);
Collection.prototype.push.apply(collection, this.filter(function(o) {
return (o instanceof type || o === new type(o).valueOf());
}));
return collection;
},
item: function(index) {
return this.getObjects()[ index ];
},
isEmpty: function() {
return this.getObjects().length === 0;
},
contains: function(object) {
return this.getObjects().indexOf(object) > -1;
}
});
kk.Collection = Collection;
})();
})(window, window.document);
var collec = new kk.Collection(String);
collec.push('lol', 'lol2'); // Sans chainage, ca fonctionne
console.log(collec);
collec.push('lol', 'lol2').push('lol3'); // Avec, une erreur est déclanchée.
console.log(collec);
Modifié par ChibiKookie (02 Sep 2014 - 13:51)