Definir objetos, sus atributos y comportamiento de objetos javascript

Esquema que resume cómo definir los objetos, atributos de objetos, y comportamiento de los atributos y de los objetos en JavaScript.

JavaScriptObject

Descargar esquema [png]

Anuncios
Definir objetos, sus atributos y comportamiento de objetos javascript

Empezar a utilizar Grunt

Como programador front-end hay ciertas tareas que pueden repetirse a diario como:

  • Modularizar el CSS pero posteriormente concatenarlos en unos pocos archivos css en su versión de producción. Lo mismo para el JavaScript.
  • Comprimir el CSS y el JavaScript para conseguir un tamaño menor de los ficheros cuando se ponen en producción.
  • Realizar una optimización de todas las imágenes utilizadas.
  • Compilar el código de Less, Sass, SCSS, etc a código real CSS.

logo de gruntjs

La lista anterior, que desde luego no es una lista completa de las tareas de un front-end, pero son cosas que tenemos que hacer, podemos decir que es una lista de tareas.

Pues bien, Grunt, del que seguro que ya has oído hablar,  resulta que es un gestor de tareas. Grunt puede realizar tareas automáticas, como las indicadas anteriormente,  que apenas requieran de nuestro maravilloso talento. Simplemente tendremos que abrir la línea de comandos, ir hasta el directorio raíz de nuestro proyecto, escribir grunt y darle al return. Así de sencillo. Obviamente es necesario configurarlo antes, y ahí es donde nos podemos quedar atascados ya que en contra de la forma en que lo venden, no es algo tan trivial.

Y como creo que Grunt es más conocido de lo que luego en realidad se usa, he decidido escribir este post en donde todos podamos ver cómo configurarlo para un proyecto web.

Lo primero que debemos saber es que Grunt se ejecuta sobre Node, por lo que deberemos tener Node instalado. La instalación de Node a día de hoy es trivial (siguiente, siguiente, siguiente y  finalizar).

Instalar Grunt

Primero abrimos una ventana de comandos con permisos de administrador y vamos hasta el directorio raíz de nuestro proyecto. Escribimos el siguiente comando:

npm install -g grunt-cli

Con esto instalamos la interfaz de línea de comandos de Grunt de forma global.

grunt-packagejson

 

Después necesitaremos un fichero en la raíz de tu proyecto llamado package.json. Este fichero define cómo Node y NPM trata las dependencias. Una vez tenemos el package.json en su sitio e indicando que grunt es una dependencia, podemos teclear el siguiente comando:

npm install

Y veremos que se crea una nueva carpeta llamada node_modules, que es donde se nos han descargado todas las dependencias necesarias.

grunt-node_modules

Concatenar ficheros con Grunt

Ya tenemos Grunt instalado y vemos que en nuestro proyecto tenemos tres ficheros de javascript responsables de realizar 3 peticiones al servidor que podríamos reducirlos a un sólo fichero y por lo tanto a una sola llamada al servidor.

  • plugins.js
  • main.js
  • carrusel.js

En producción, concatenaremos estos tres ficheros en uno, produccion.js. Tenemos que indicarle a Grunt que lo haga. El plugin oficial de Grunt para concatener ficheros se llama grunt-contrib-concat. En su página podemos leer que para incluirlo como dependencia es necesario ejecutar el siguiente comando:

npm install grunt-contrib-concat --save-dev

Si ahora volvemos a nuestro package.json veremos que se ha añadido la línea:

“grunt-contrib-concat”: “^0.5.1”

Para usar este plugin necesitamos empezar a configurar Grunt para que realmente lo utilice tal y como nosotros queremos. Para ello vamos a crear al mismo nivel que package.json un fichero llamado Gruntfile.js (ojo con la G mayúscula)

module.exports = function ( grunt ) {
  // La configuración de Grunt va aquí
  
  grunt.initConfig({
    pkg: grunt.file.readJSON( 'package.json' ), //lectura del package.json
    
    concat: {
      //La configuración para concatenar los fichero va aquí
    }

  });

  // Le decimos a Grunt que queremos usar grunt-contrib-concat
  grunt.loadNpmTasks( 'grunt-contrib-concat' );

  // Donde le decimos a Grunt qué hacer cuando teclearmos "grunt" en la consola.
  grunt.registerTask('default', [ 'concat' ] );

};

Hay que seguir la sintaxis anterior en donde se puede ver por los comentarios, de qué va el asunto.

concat: {
      dist: {
        src : [ 'js/plugins.js', 'js/carrusel.js', 'js/main.js' ],
        dest: 'build/js/produccion.js'
      }
}

Aquí, en el fichero Gruntfile.js hemos incluido dentro de la tarea concat, la sintaxis necesaria para concatenar los tres ficheros js en uno solo llamado produccion.js que está en la subcarpeta js de la carpeta build. src es de source y dest de destination.

Para ejecutarlo tecleamos

grunt

Y si todo ha ido bien, ¡Mágia!. Grunt pasa a ejecutar nuestra tarea default que lanzará a su vez la tarea ‘concat‘. Vemos que aunque no existía la carpeta build, Grunt la ha generado.

grunt-concat

Dejaré para futuros post cómo hacer que Grunt haga otras tareas muy comunes por nosotros como minificar javascript, optimizar imágenes.

 

 

Empezar a utilizar Grunt

Propiedades enumerables de un objeto javascript

 

Por defecto, todas las propiedades que se añaden a un objeto son de tipo enumerable, por lo cual, se puede iterar por ellas utilizando el loop for-in.

 

var propiedad;
for ( propiedad in objeto ) {
  console.log( "Nombre: " + propiedad );
  console.log( "Valor: " + objeto[ propiedad ] );
}

Si necesitas una lista de propiedades enumerable de un objeto ECMAScript5 introdujo el método Object.keys() que devuelve un array de String con los nombres de las propiedades del objeto.

var propiedades = Object.keys(objeto);

Hay una diferencia entre las propiedades por las que itera el loop for-in y las que devuelve el método Object.keys(). El loop for-in incluye las propiedades prototype del objeto mientras que Object.keys() solo nos proporciona las own properties.

Ten en cuenta que no todas las propiedades son enumerables. De hecho, la mayoría de las propiedades prototype no lo son. Puedes comprobar si una propiedad es enumerable utilizando el método propertyIsEnumerable().

var persona = {
  nombre: "Aitor"
};
console.log( "nombre" in persona ); //true
console.log( persona.propertyIsEnumerable( "nombre" ) ); /true

var propiedades = Object.keys( persona ); //devuelve un Array

console.log( "length" in propiedades ); //operador in devuelve true
console.log( propiedades.propertyIsEnumerable( "length" ) ); //false

Aquí, la propiedad nombre del objeto persona es enumerable. En cambio, la propiedad length del array no es un enumerable ya que forma parte de Array.prototype que heredan todos los arrays, es decir, es una prototype property.

Propiedades enumerables de un objeto javascript

Borrar propiedades de un objeto en javascript

Lo mismo que las propiedades puede añadirse en cualquier momento, también se pueden borrar. El dar un valor de null a la propiedad no hace que ésta se borre realmente. Necesitas usar el operador delete.

jsCuando el operador delete ha borrado la propiedad con éxito, nos devolverá true (algunas propiedades no se pueden borrar).

En el siguiente ejemplo se ve la forma en cómo usar el operador delete.

var persona = {
  nombre: "Aitor",
  edad: 41
};
console.log( "nombre" in persona ); //true
delete persona.nombre;
console.log( "nombre" in persona ); //false
console.log( persona.nombre ); // undefined

En el ejemplo también se puede ver que si se intenta acceder a una propiedad ya inexistente, simplemente nos devolverá undefined, pero no se lanzará ninguna excepción de error.

 

Borrar propiedades de un objeto en javascript

Detectar correctamente propiedades de un objeto JavaScript

jsComo las propiedades en JavaScript pueden ser añadidas a un objeto en cualquier momento, a veces es necesario comprobar si dicha propiedad existe.

Se suele ver a menudo que esta tarea se realiza siguiendo el patrón:

if (persona.edad){
  //hacer algo con la edad
}

El problema con este patrón es que JavaScript evalúa como falso cualquier valor que sea:

  • null
  • undefined
  • false
  • NaN
  • “” (string vacío)

Como la propiedad puede contener uno de los anteriores valores el chequeo anterior puede dar falsos negativos.

Por ejemplo, si la edad de persona fuera 0, la condición se evaluará como false incluso aunque la propiedad exista.

Una forma de realizar la comprobación de si una propiedad existe sería con el operador in. El operador in busca la propiedad en el objeto y devuelve true si la encuentra.

var persona = {
  nombre: "Aitor",
  edad: 41,
  saludar: function(){
    console.log( "Hola, soy " + this.nombre );
  }
};

console.log( "nombre" in persona); // true
console.log( "edad" in persona); // true
console.log( "apellidos" in persona); // false
console.log( "saudar" in persona); // true

Ten en cuenta que los métodos también son propiedades y por lo tanto también puedes usar el operador in para detectarlos, como puedes ver en el ejemplo del método saludar().

En la mayoría de los casos, el operador in es la mejor forma de determinar si la propiedad existe. En otros casos sin embargo, puede que necesites comprobar la existencia de una propiedad no heredada, de las que están en el prototype. Para entendernos, si realizamos

console.log( "toString" in persona)

nos devolverá true.

Si necesitamos detectar si existe una propiedad de las llamadas own properties, deberemos usar el método hasOwnProperty().

console.log( "nombre" in persona); //true
console.log( persona.hasOwnProperty( "nombre" )); //true
console.log( "toString" in persona); //true
console.log( persona.hasOwnProperty( "toString" )); //false

Si hasta ahora has utilizado el patrón mostrado al principio y te están entrando sudores fríos, recuerda que a partir de ahora debes utilizar para detectar si existe una propiedad en un objeto:

  • el operador in (para own properties y prototype properties)
  • el método hasOwnProperty()  (sólo para own properties)

 

Detectar correctamente propiedades de un objeto JavaScript

Utilizando requireJS

Veamos cómo es posible cargar ficheros de javascript según los necesitemos en nuestro proyecto de forma dinámica. Para ello podemos usar la librería requireJS.

Indicar que es necesario hacer el siguiente taller a través de un servidor HTTP, si no requireJS dará error ya que no podrá realizar su cometido.

Creamos un proyecto con un esquema como el siguiente:

require-1

Vamos a importar a través de requireJS las librerías sumar.js y multiplicar.js que vamos a necesitar desde el index. El contenido de estos scripts es:


sumar.js:
function sumar(arg1, arg2){
    return arg1 + arg2;
}

multiplicar.js:
function multiplicar (arg1, arg2) {
    return arg1 * arg2;
}

 

Haremos uso de estas interesantes librerías desde app.js pero en un principo, en el index.html, sólo tenemos importados los scripts de require.js y app.js.

require-3

require.js nos proporciona dos funciones en las que está la clave de todo:

  • define(nombreModulo, modulosRequeridos, definiciónModulo)
  • require(modulosRequeridos, definiciónModulo)

En este caso vamos a ir a lo más sencillo de uso de require.js y sólo vamos a ver la utilización del método require(). Dejo para otro taller el uso de define().

Desde app.js será necesario requerir tanto sumar.js como multiplicar.js. Esto se hace de la siguiente manera (muy al estilo de AngularJS):


app.js:
require([ "js/sumar.js", "js/multiplicar.js" ], function(){
    alert( sumar(5,10) );
    alert( multiplicar(5,10) );
});

Una vez dentro del callback de require() ya podemos disponer de sumar.js y multiplicar.js tal y como si estuvieran importadas.

De esta forma, que es la forma más sencilla de usar requireJS, podemos ahorrarnos el tener que ir con una armadura de scripts constantemente a todas las páginas web que se visiten.

Aquí vemos desde las devtools de Chrome que realmente sumar.js y multiplicar.js se han cargado posteriormente.

require-2

Utilizando requireJS

Versionamiento Semántico

Existe en el desarrollo de software actual, en el que se utiliza un innumerable número de frameworks, micro frameworks, librerías y otras hierbas, surge la pesadilla de mantener una gestion de dependencias entre unas librerías con otras.

semver

Por eso existe una convención para etiquetar las versiones de software que nos conviene mantener. En este post comento de forma resumida en qué consiste dicha convención, llamada SemVer.

La sintaxis de versión es:

 

MAJOR . MINOR . PATCH

 

  1. PATCH: Cuando se producen cambios menores, típicamente arreglos de bugs que en ningún momento interfieren en la compatibilidad con la versión anterior.
  2. MINOR: Cuando se introducen nuevas funcionalidades o unas mejoras notables sobre las funcionalidades anteriores. Tampoco interfiere en la compatibilidad.
  3. MAJOR: Gran cantidad de cambios, o aún siendo pocos cambios, éstos son muy significativos, abandono de soporte a funcionalidades deprecated. Puede interferir, y de hecho lo suele hacer, en la compatiblidad con versiones anteriores.

Así que si en en nuestro proyecto actualizamos a nueva versión major es necesario realizar una batería completa de pruebas. Se pueden utilizar los gestores de descargas de librerías como bower o composer para tener controlada y automatizada la actualización de librerías.

Versionamiento Semántico