Creando objetos y aplicaciones configurables en Javascript

24 Ene 2012

Introducción

Aquellos que estén más familiarizados con la programación de plugins para jQuery, conocen de sobra el método $.extend() de esta biblioteca. Gracias a él, podemos definir una serie de valores por defecto para nuestras aplicaciones (objetos) que se sobreescriben solo en caso de que éstos se especifiquen a su inicialización.

Este tipo de comportamiento, que identificable con el concepto de herencia clásica en la POO, podemos obtenerlo también en nuestras aplicaciones sin necesidad de recurrir a bibliotecas de terceros.

Veamos una forma sencilla de crear un objeto con una serie de valores por defecto que pueden ser sobreescritos desde su propia API.

El método Extend

Lo primero que tenemos que hacer es crear una función que nos permita ‘extender’ fácilmente un objeto preexistente.

Para este ejercicio, vamos a considerar el extender la primitiva nativa Object de Javascript.

NOTA: Sobre el hecho de extender primitivas, se ha escrito mucho. Si no nos gusta esta vía, siempre podemos crear una función simple que nos haga el trabajo. Para ver las ventajas o problemas de cada uno de estos métodos, se recomienda la lectura del artículo «Extending Javascript Natives» del bueno de Angus Croll.

El código, muy simple, sería:

Object.prototype.extend = Object.prototype.extend || function(destination, source) {
  for (var property in source)
    destination[property] = source[property];
  return destination;
};

Con esto, hemos extendido a Object con un nuevo método extend. Este método aceptaría dos argumentos: el objeto destino (destination) que presumiblemente ya cuenta con una serie de valores establecidos y el objeto origen (source) que debe sobreescribir el anterior allí donde haya coincidencias.

El método anterior podríamos complicarlo mucho más con comprobaciones de todo tipo, pero para la intención de este artículo, con la funcionalidad indicada es suficiente: se trata de un bucle que recorre las propiedades del objeto source y las va escribiendo en el objeto destination. Finalmente, devuelve este último objeto ya modidificado.

Implementando el nuevo método

Tomemos ahora el siguiente escenario: estamos desarrollando una aplicación, biblioteca o plugin y necesitamos asignarle una serie de valores por defecto. Estos valores permiten mucha flexibilidad a la hora de configurar nuestra funcionalidad.

Por ejemplo:

var my App = function(){
 
  // Default settings
  var settings = {
    fullScreen : true,
    backgroundColor : '#000',
    speed : 20
    /* and so on... */
  };
 
};

Se trataría en este caso de ir añadiendo propiedades que más adelante necesitaremos que estén iniciadas con algún tipo de valor por defecto. En el código anterior, hemos incluido como ejemplo una opción para una supuesta pantalla completa, un color de fondo y algún parámetro de velocidad. Podría ser este el código inicial de un carrusel o un slideshow tradicional.

Tendríamos ahora que permitir mediante un API de esta biblioteca, que el usuario o desarrollador pudiera sobreescribir estos valores para configurar la herramienta a su gusto. Algo que permitiera, por ejemplo:

myApp({
  fullScreen : false,
  backgroundColor : '#FFF'
});

La idea sería modificar en tiempo de ejecución los valores por defecto anteriores para que tanto la propiedad fullScreen como backgroundColor tomasen los nuevos valores. Por omisión, speed conservaría su valor inicial.

Para implementar esta funcionalidad a través de nuestro nuevo método extend, solo tendríamos que hacer una pequeña modificación en el código de nuestra biblioteca-aplicación:

var myApp = function(customSettings){
  // Default settings
  var settings = {
    fullScreen : true,
    backgroundColor : '#000',
    speed : 20
    /* and so on... */
  };
 
  customSettings || ( customSettings = {} );
 
  Object.extend( settings, customSettings );  
 
  /* Awesome more methods goes here */
 
  return settings; // Only for testing
 
};

Y ya lo tendríamos!

Nuestro objeto se inicia con una serie de valores por defecto, pero ahora, acepta además un argumento que se corresponde con las opciones introducidas por el desarrollador o usuario.

Estas customSettings extienden a las default settings modificando sus valores en tiempo de ejecución. El return no sería necesario en una aplicación real, pero para este ejercicio permite ver cómo hemos efectivamente modificado los valores iniciales.

Podemos comprobarlo si ahora ejecutamos el ejemplo anterior:

var test = myApp({
  fullScreen : false,
  backgroundColor : '#FFF'
});
 
console.log(test);

El resultado que obtenemos son nuestras opciones de configuración modificadas salvo en aquellos casos en los que, por omisión, se mantienen las establecidas por defecto. Cualquier método a partir de ahí en nuestra aplicación podría disponer de estos valores para realizar las operaciones y funcionalidades oportunas.

Conclusión

Con esta sencilla fórmula, podemos crear aplicaciones muy flexibles que permitan un alto grado de configuración. Se trata del mismo principio aplicado a muchas bibliotecas de terceros como pueden ser, por ejemplo, los plugins de jQuery.

Más:

{3} Comentarios.

  1. yeikos

    Un poco más elaborada, pero igual de simple, permitiendo múltiples objetos y cuyo uso más interesante quizá sea el siguiente: extend({}, settings, { speed: 15 });

    Es decir, mantenemos intacto settings y operamos sobre un nuevo objeto.

    En el código que escribiste daría igual, ya que declaras settings con cada llamada a la función, pero si no fuera así se tendría que recurrir a lo dicho anteriormente.

    function extend() {
      var x = [].slice.call(arguments),
        y = x.shift();
      
      x.forEach(function(z) {
        Object.getOwnPropertyNames(z).forEach(function(w) {
          Object.defineProperty(y, w, Object.getOwnPropertyDescriptor(z, w));
        });
      });
    
      return y;
    }
    
  2. Antonio Pantoja

    Fenomenal el tutorial

  3. seguridad en javascript

    Hola man

    Estoy utilizando un plugin de Firefox llamado No Script, al entrar a tu sitio me manda un mensaje diciendo que ha filtrado un posible intento de XSS, al parecer esto ocurre por el plugin de Twitter de tu página, de igual forma al entrar a otro sitio me apareció un mensaje parecido, ya que tu eres conocedor de Javascript tal vez podrías hacer un artículo sobre XSS realizado por plugins insertados en páginas web.

    Thanx

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *