Contenido

Mejorando rendimientos de las técnicas de POO en Javascript

10 mar

+ 5

Hace unas semanas vimos el rendimiento que ofrecían las diferentes técnicas que proporcionan la posibilidad de añadir Orientación a Clases a nuestros scripts en Javascript.

En las pruebas realizadas por Broofa, vimos que los resultados daban como ganador al script de John Resig que dejaba a los demás a la altura del betún. Algo sorprendente en tan solo 25 líneas de código.

class_performance_javascript

JotaClass

jDeveloper (o Jota) nos deleitó con jClass2k, una implementación propia que estuvimos puliendo durante unos días para intentar mejorar los resultados obtenidos.

var JotaClass = function(current,previous){
      previous = typeof previous == 'undefined' ? {} : previous.prototype;
      for(p in previous){
            if(typeof current[p] == 'undefined') current[p] = previous[p];
            else if(typeof previous[p] == 'function'){
                  current[p] = (function(tmp){
                                var _parent = function(){
                                    this.parent = _parent.parent;
                                    return tmp.apply(this, arguments);
                                    }
                                    return _parent;
                                })(current[p]);
                current[p].parent = previous[p];
            }
        }
        var construct = function(){
          if(this.init) this.init.apply(this,arguments);
        }
        construct.prototype = current;
        construct.constructor = JotaClass;
        return construct;
    }
//Modo de empleo
var Hobbit = new JotaClass({
		bailar: function(){
			.....
		}
});

var Frodo = new JotaClass({
		anillo: true;
		desaparecer: function(){
			if (this.anillo)
				this.display("none");
		}
	},Hobbit);

JoseanpgClass

En este proceso Jose Antonio Perez (Joseanpg) se añadió para ilustrarnos con su experiencia y ayudarnos a pulir el script y obtener mejores resultados. A partir de ahí, salió otra implementación que podemos ver a continuación.

function makeParent(fn, parent) {
	      return function() {
	         this.parent = parent;
	         return fn.apply(this, arguments);
	      }
  }
var JoseanpgClass = function(current,previous){
   previous = typeof previous == 'undefined' ? {} : previous.prototype;
   for(p in previous)
	 current[p] = (typeof previous[p] == 'function')?makeParent(current[p], previous[p]):previous[p];
   var construct = function(){ if(this.init) this.init.apply(this,arguments);}
   construct.prototype = current;
   construct.constructor = JoseanpgClass;
   return construct;
}
//Modo de empleo
var Hobbit = new JoseanpgClass({
	bailar: function(){
		.....
	}
});

var Frodo = new JoseanpgClass({
	anillo: true;
	desaparecer: function(){
		if (this.anillo)
		this.display("none");
	}
},Hobbit);

Klass

Como me dió envidia, decidí implementar mi propia versión. Basada en el script de John Resig y sacando alguna idea de los scripts anteriores.

var Klass = function(prop) {
        var klass = function(){ if(this.init) this.init.apply(this, arguments);};
        klass.prototype = prop || {};
        klass.constructor = Klass;
        klass.extend = Klass.extend;
        return klass;
};

Klass.extend = function(prop){
	function setParent(fn, parent) {
		      return function() {
		         this.parent = parent;
		         return fn.apply(this, arguments);
		      }
	  }
	function merge(prev, next){
			for (var name in next){
				if (prev[name] && (typeof prev[name] == 'object' && typeof next[name] == 'object'))
					merge(prev[name], next[name]);
				else
					prev[name] = next[name];
			}
		return prev;
	};

      for (var name in this.prototype) {
		if (!prop[name])
			prop[name] = this.prototype[name];
		else if(typeof prop[name] == 'function' && typeof this.prototype[name] == 'function')
          prop[name] = setParent(prop[name], this.prototype[name]);
		else if(typeof prop[name] == 'object' && typeof this.prototype[name] == 'object')
          prop[name] = merge(prop[name], this.prototype[name]);
      }
  return new Klass(prop);
};
//Modo de uso
var Hobbit = Klass({
	bailar: function(){
		.....
	}
});

var Frodo = Hobbit.extend({
	anillo: true;
	desaparecer: function(){
	    if (this.anillo)
		this.display("none");
	}
});

Resultados

He montado un test basado en JSLitmus, osea que nos cuenta el número de operaciones por segundo (mientras más mejor) para testear nuestras implementaciones frente a la de John Resig (la más rápida de las anteriores). Para los que lo sepan, la versión Ad Hoc, es la montada nativamente.

firefoxsafari4opera

Ir al test

No he podido probar en más navegadores y todo está probado sobre Mac OS. Es interesante ver como, en todas las pruebas, siempre sobrepasamos (alguna implementación) la implementación de John Resig.

Actualización

He podido probar sobre Windows con diferentes navegadores, veamos los resultados:
Firefox 3.0.7
Gráfico Windows/Firefox

Opera 9.63
Windows/Opera

Internet Explorer 6
Windows/Internet Explorer 6
Internet Explorer 7.0
Windows/Internet Explorer 7

Safari 4
Windows/Safari4

Google Chrome
Windows/Google Chrome

Comentar

#

Me reservo el derecho de eliminar y/o modificar los comentarios que contengan lenguaje inapropiado, spam u otras conductas no apropiadas en una comunidad civilizada. Si tu comentario no aparece, puede ser que akismet lo haya capturado, cada día lo reviso y lo coloco en su lugar. Siento las molestias.