Autor Tema: Extendiendo Javascript  (Leído 1880 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado JaiMe

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 1485
  • λ | h+
Extendiendo Javascript
« : enero 24, 2011, 12:55:17 am »
En esta entrada hablare un poco sobre como crear una librería en JavaScript para aumentar la funcionalidad del lenguaje y evitar tareas repetitivas.

Funciones

Las funciones son unidades modulares que contienen expresiones y nos ayudan a organizar nuestro código en componentes reusables. Consideremos la siguiente función(originalmente publicada por mxgxw en trocitos de codigo) que evalúa un numero y regresa el dígito de acuerdo a su posición:

Código: [Seleccionar]
function pos(n, p) {
    return !isNaN(p) && !isNaN(n) && p !== 0 ?
            Math.floor((n / Math.pow(10, p > 0 ? --p : p )) % 10) : 0;
}

Por ejemplo, si tenemos el numero 345.67 podríamos obtener un digito especifico:
Código: [Seleccionar]
[3 4 5 .  6  7 ]
 | | |    |  |
[3 2 1 0 -1 -2]


Empleando la función para evaluar el numero 12345.6789 obtendríamos:

Código: [Seleccionar]
pos(12345.6789, -4)           // returns 9
pos(12345.6789, -1)           // returns 6
pos(12345.6789, 0)            // returns 0
pos(12345.6789, 1)            // returns 5
pos(12345.6789, 4)            // returns 2
pos(12345.6789, {'x':'10'})   // returns 0 por que el segundo argumento no es un numero

Extendiendo Objetos Nativos

Una manera extender la funcionalidad de JavaScript es mediante la modificación de los objetos nativos. Por ejemplo, si deseamos que nuestra función pos() este disponible para todos los números en JavaScript solo tendríamos que agregar la función al prototipo del objeto nativo Number.

Código: [Seleccionar]
Number.prototype.pos = function(p) {
    return typeof p ==='number' && p !== 0 ?
            Math.floor( ( parseFloat(this) / Math.pow(10, p > 0 ? --p : p ) ) % 10) : 0;
};

En Javascript herencia es en base a prototipos y las funciones son ciudadanos de primera clase, lo ultimo significa que podemos pasar una función como argumento a otra función u asignarla a una variable. En este caso, he agregado un nuevo miembro pos al prototipo del objeto numero y asignado la función pos()

Con estos cambios podríamos ejecutar la función de la siguiente manera:

Código: [Seleccionar]
(12345.6789).pos(1)     // 5
(12345.6789).pos(-1)    // 6

El ejemplo anterior puede ser replicado en otros objetos, por ejemplo si deseamos reducir la longitud de una cadena de texto, tendriamos que aumentar el prototipo del objeto String:

Código: [Seleccionar]
String.prototype.wrap = function(max){
    return (this.length > max) ? this.substring(0, max) + '...' : '';
};

var str = 'Esta es una cadena laaaaaaaaaaaaaaaaaaaaaaaaaaaaga de texto';

str.wrap(10)           // esta es un...

Sin embargo, aumentar los objetos nativos de esta manera no es recomendable, debido a que podríamos crear conflictos de compatibilidad con otras librerías e incluso implementaciones del lenguaje en diferentes navegadores. Una manera de evitar esto es verificando si cierto prototipo tiene un miembro especifico, de ser falso entonces podríamos extenderlo.

Encapsulando Nueva Funcionalidad

La manera mas aceptable de expandir el lenguaje es por medio del uso de librerías con toda su funcionalidad encapsulada y cuyo impacto en el namespace global sea mínimo. Esto puede ser logrado a través de funciones anónimas auto-ejecutables.

Código: [Seleccionar]
// función anónima -> es una declaración
function(){ }

// función anónima en paréntesis ->  es una expresión
( function(){ } );

// función anónima auto-ejecutable -> paréntesis extra la hacen una invocación
( function(){ } ) () ;

// este estilo también es aceptable y puede ayudar a clarificar el codigo
( function(){ }() ) ;

En el siguiente ejemplo la función auto-ejecutable muestra un mensaje de alerta:

Código: [Seleccionar]
(function(){
    alert("Hola!");
 }());

Construyendo una Libreria
La función auto-ejecutable tiene acceso a los objetos que han sido declarados afuera de ella, pero todo declarado adentro esta disponible solo para ella misma, de esta manera, la información se mantiene contenida y debidamente encapsulada.

Código: [Seleccionar]
(function() {

    var lib = window.lib = {};

    lib.pos = function(n, p) {
        return this.isNum(p) && this.isNum(n) && p !== 0 ?
                Math.floor((n / Math.pow(10, p > 0 ? --p : p)) % 10) : 0;
    };

    lib.isNum = function(x){
        return typeof x==='number';
    };
}());

Entonces, como utilizamos toda la funcionalidad de la librería desde afuera? Primero creamos un objeto vació {}, luego asignamos este objeto a la propiedad lib del objeto window. Esta propiedad es automáticamente creada por el interprete por medio de la expresión window.lib.

Código: [Seleccionar]
var lib = window.lib = {};
Tambien creamos una variable lib que funcionaria como un alias para uso interno, de esta manera para agregar funcionalidad a la librería, solo tendríamos que crear nuevos miembros para lib y asignarle nuevos metodos.

Código: [Seleccionar]
lib.metodo = function() {
    // implementacion
};

Para utilizar la librería solamente tendríamos que llamar a sus metodos por medio de window.lib() o simplemente lib() por ejemplo:

Código: [Seleccionar]
lib.pos(12345.6789, 1);   // returns 5
lib.pos(12345.6789,-1);   // returns 6

Espero que este post haya sido de ayuda.


Editado, para mayor comprensión y claridad.
« Última Modificación: marzo 16, 2011, 10:06:12 pm por JaiMe »
"Unless you try to do something beyond what you have already mastered, you will never grow."
― Ralph Waldo Emerson

Desconectado hkadejo

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 3345
Re: Extendiendo Javascript
« Respuesta #1 : abril 26, 2011, 10:30:58 pm »
Man aunque nadie te haga caso con estas micro clases de Javascript, deberias seguirlas a mi me sirvio este post para terminar de entender algunos conceptos  :thumbsup:

Desconectado JaiMe

  • Global Moderator
  • The Communiter-
  • *
  • Mensajes: 1485
  • λ | h+
Re: Extendiendo Javascript
« Respuesta #2 : abril 27, 2011, 06:38:26 pm »
Que bien que te haya servido.

Cuando aprendo nuevos conceptos o quiero entenderlos mas a fondo escribo pequeños ejemplos con bastantes comentarios - generalmente en ingles. De ahi surge este post.

Quizas algun dia me anime a abrir un blog en español para discutir temas similares al estilo de t.h.e.c.h.a.n.g.e.l.o.g.
"Unless you try to do something beyond what you have already mastered, you will never grow."
― Ralph Waldo Emerson