miFuncion(); // = undefined al mandar a llamar la función
// Las funciones en JavaScript son de primera clase, así que pueden ser asignadas
// a variables y pasadas a otras funciones como argumentos - por ejemplo:
function miFuncion(){
// este código será llamado cada cinco segundos
}
setTimeout(miFuncion, 5000);
// Note: setTimeout no es parte de JS, pero lo puedes obtener de los browsers
// y Node.js.
// Es posible declarar funciones sin nombre - se llaman funciones anónimas
// y se definen como argumentos de otras funciones.
setTimeout(function(){
// este código se ejecuta cada cinco segundos
}, 5000);
// JavaScript tiene ámbitos de funciones; las funciones tienen su propio ámbito pero
// otros bloques no.
if (true){
var i = 5;
}
i; // = 5 - en un lenguaje que da ámbitos por bloque esto sería undefined, pero no aquí.
// Este conlleva a un patrón de diseño común llamado "ejecutar funciones anónimas
//inmediatamente", que preveé variables temporales de fugarse al ámbito global
(function(){
var temporal = 5;
// Podemos accesar al ámbito global asignando al 'objeto global', el cual
// en un navegador siempre es 'window'. El objeto global puede tener
// un nombre diferente en ambientes distintos, por ejemplo Node.js .
window.permanente = 10;
})();
temporal; // da ReferenceError
permanente; // = 10
// Una de las características más útiles de JavaScript son los closures.
// Si una función es definida dentro de otra función, la función interna tiene acceso
// a todas las variables de la función externa, incluso aunque la función
// externa ya haya terminado.
function decirHolaCadaCincoSegundos(nombre){
var texto = "¡Hola, " + nombre + "!";
// Las funciones internas son puestas en el ámbito local por defecto
// como si fueran declaradas con 'var'.
function interna(){
alert(texto);
}
setTimeout(interna, 5000);
// setTimeout es asíncrono, así que la funcion decirHolaCadaCincoSegundos
// terminará inmediatamente, y setTimeout llamará a interna() a los cinco segundos
// Como interna está "cerrada dentro de" decirHolaCadaCindoSegundos, interna todavía tiene
// acceso a la variable 'texto' cuando es llamada.
}
decirHolaCadaCincoSegundos("Adam"); // mostrará una alerta con "¡Hola, Adam!" en 5s
///////////////////////////////////
// 5. Más sobre objetos; constructores y prototipos
// Los objetos pueden contener funciones.
var miObjeto = {
miFuncion: function(){
return "¡Hola Mundo!";
}
};
miObjeto.miFuncion(); // = "¡Hola Mundo!"
// Cuando las funciones de un objeto son llamadas, pueden accesar a las variables
// del objeto con la palabra clave 'this'.
miObjeto = {
miString: "¡Hola Mundo!",
miFuncion: function(){
return this.miString;
}
};
miObjeto.miFuncion(); // = "¡Hola Mundo!"
// Las funciones de un objeto deben ser llamadas dentro del contexto de ese objeto.
var miFuncion = myObj.miFuncion;
miFuncion(); // = undefined
// Una función puede ser asignada al objeto y ganar acceso a él gracias a esto,
// incluso si no estaba dentro del objeto cuando este se definió.
var miOtraFuncion = function(){
return this.miString.toUpperCase();
}
miObjeto.miOtraFuncion = myOtherFunc;
miObjeto.miOtraFuncion(); // = "¡HOLA MUNDO!"
// Podemos especificar el contexto en el que una función será llamada con los comandos
// 'call' o 'apply'.
var otraFuncion = function(otroString){
return this.miString + otroString;
}
otraFuncion.call(miObjeto, " y hola Luna!"); // = "¡Hola Mundo! y hola Luna!"
// 'apply' es casi idéntico, pero recibe un arreglo como argumento.
otraFuncion.apply(miObjeto, [" y hola Sol!"]); // = "¡Hola Mundo! y hola Sol!"
// Esto es útil cuando estás trabajando con una función que acepta una secuencia de
// argumentos y quieres pasar un arreglo.
Math.min(42, 6, 27); // = 6
Math.min([42, 6, 27]); // = NaN (uh-oh!)
Math.min.apply(Math, [42, 6, 27]); // = 6
// Pero 'call' y 'apply' sólo son temporales. Cuando queremos que se quede, usamos bind.
var funcionUnida = otraFuncion.bind(miObjeto);
funcionUnida(" y hola Saturno!"); // = "¡Hola Mundo! y hola Saturno!"
// Bind también puede ser usada para aplicar parcialmente (curry) una función.
var producto = function(a, b){ return a * b; }
var porDos = producto.bind(this, 2);
porDos(8); // = 16
// Cuando llamas a una función con la palabra clave 'new' un nuevo objeto es creado.
// Se hace disponible a la función. Las funciones diseñadas para ser usadas así se
// llaman constructores.
var MiConstructor = function(){
this.miNumero = 5;
}
miNuevoObjeto = new MiConstructor(); // = {miNumero: 5}
miNuevoObjeto.miNumero; // = 5
// Todos los objetos JavaScript tienen un 'prototipo'. Cuando vas a accesar a una
// propiedad en un objeto que no existe en el objeto el intérprete buscará en
// el prototipo.
// Algunas implementaciones de JavaScript te permiten accesar al prototipo de
// un objeto con la propiedad __proto__. Mientras que esto es útil para explicar
// prototipos, no es parte del estándar; veremos formas estándar de usar prototipos
// más adelante.
var miObjeto = {
miString: "¡Hola Mundo!"
};
var miPrototipo = {
sentidoDeLaVida: 42,
miFuncion: function(){
return this.miString.toLowerCase()
}
};
miObjeto.__proto__ = miPrototipo;
miObjeto.sentidoDeLaVida; // = 42
// Esto funcionan también para funciones.
miObjeto.miFuncion(); // = "hello world!"
// Por supuesto, si la propiedad que buscas no está en el prototipo,
// se buscará en el prototipo del prototipo.
miPrototipo.__proto__ = {
miBoolean: true
};
miObjeto.miBoolean; // = true
// Esto no involucra ningún copiado, cada objeto guarda una referencia a su
// prototipo. Esto significa que podemos alterar el prototipo y nuestros
// cambios serán reflejados en todos lados.
miPrototipo.sentidoDeLaVida = 43;
miObjeto.sentidoDeLaVida; // = 43
// Mencionabamos anteriormente que __proto__ no está estandarizado, y que no
// existe una forma estándar de accesar al prototipo de un objeto. De todas formas.
// hay dos formas de crear un nuevo objeto con un prototipo dado.
// El primer método es Object.create, el cual es una adición reciente a JavaScript,
// y por lo tanto, no disponible para todas las implementaciones aún.
var miObjeto = Object.create(miPrototipo);
miObjeto.sentidoDeLaVida; // = 43
// El segundo método, el cual trabaja en todos lados, tiene que ver con los
// constructores. Los constructores tienen una propiedad llamada prototype.
// Este NO ES el prototipo de la función constructor; es el prototipo que
// se le da a los nuevos objetos cuando son creados con la palabra clave
// new.
MiConstructor.prototype = {
miNumero: 5,
getMiNumero: function(){
return this.miNumero;
}
};
var miNuevoObjeto2 = new MiConstructor();
miNuevoObjeto2.getMiNumero(); // = 5
miNuevoObjeto2.miNumero = 6
miNuevoObjeto2.getMiNumero(); // = 6
// Los tipos que vienen por defecto en JavaScript (como Strings y números)
// también tienen constructores que crean objetos equivalentes.
var miNumero = 12;
var miNumeroObjeto = new Number(12);
miNumero == miNumeroObjeto; // = true
// No son exactamente iguales.
typeof(miNumero); // = 'number'
typeof(miNumeroObjeto); // = 'object'
miNumero === miNumeroObjeyo; // = false
if (0){
// Este código no se ejecutara porque 0 es false.
}
if (Number(0)){
// Este código sí se ejecutara, puesto que Number(0) es true.
}
// Aún así, los objetos que envuelven y los prototipos por defecto comparten
// un prototipo. así que puedes agregar funcionalidades a un string de la
// siguiente forma:
String.prototype.primerCaracter = function(){
return this.charAt(0);
}
"abc".primerCaracter(); // = "a"
// Este hecho se usa normalmente en "polyfilling", lo cual es implementar
// nuevas funciones a JavaScript en un JavaScript más viejo, así que pueda ser
// compatible con ambintes más viejos de JavaScript (por ejemplo, navegadores viejos).
// Por ejemplo, mencionabamos que Object.create no está aún disponible en todas
// las implementaciones, pero podemos hacerlo con polyfill:
if (Object.create === undefined){ // esta validación sirve para no sobreescribir
Object.create = function(proto){
// hace un constructor temporal con el prototipo correcto
var Constructor = function(){};
Constructor.prototype = proto;
// y luego lo usamos para hacer un objeto con el prototipo
// correcto.
return new Constructor();
}
}
```
## Fuentes y Referencias
La [Red para Desarroladores de Mozilla](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
proveé excelente documentación para JavaScript para navegadores. Además, está en formato de wiki,
por lo que mientras vayas aprendiendo podrás ayudar a los demás con tu experiencia.
MDN [Una re-introducción a JavaScript](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript)
cubre muchos de los conceptos que vimos aquí pero a mayor detalle. Esta guía cubre, más que nada,
el lenguaje JavaScript solo. Si quieres aprender a cómo usarlo en un ambiente web empieza aprendiendo
sobre el [DOM](https://developer.mozilla.org/en-US/docs/Using_the_W3C_DOM_Level_1_Core)
[Aprende JavaScript con ejemplos y retos](http://www.learneroo.com/modules/64/nodes/350) es una
variante de esta guía pero con retos.
[Jardín JavaScript](http://bonsaiden.github.io/JavaScript-Garden/) es una guía para todas las
funciones y características contra-intuitivas del lenguaje.
[JavaScript: La guía definitiva](http://www.amazon.com/gp/product/0596805527/) es una guía clásica / libro de referencia.
Aparte de las contribuciones directas para este artículo, algo del contenido se adaptó
del tutorial de Python por Louie Dinh en este sitio. y el [Tutorial JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript) en la Red de Desarrolladores de Mozilla.