El objetivo de la asignatura es el de aprender a resolver problemas empleando el paradigma de la Programación Orientada a Objetos (POO). Sin embargo, en este y en el siguiente capítulo se hace una introducción al lenguaje elegido para ese fin: JavaScript, tomando como base el lenguaje estudiado en la asignatura previa (C++), además, se repasan y aplican los elementos y fundamentos del paradigma de la Programación Estructurada (PE), que es el paradigma estudiado en la asignatura previa.
Como se recordará, en la programación estructurada se deben resolver los problems empleando las estructuras de control estándar: secuencia, selección e iteración y los datos deben ser organizados y manipulados (cuando no son datos simples como un número o un booleano) empleando estructuras de datos.
Por otra parte en la PE, los problemas se resuelven identificando las funciones que son necesarias para resolver el problema, empleando para ello el principio de la modularidad (el principio de divide y vencerás) donde un problema complejo se subdivide en problemas cada vez más sencillos, hasta que el subproblema es lo suficientemente sencillo como para poder ser resuelto sin difultad.
Una vez identificadas las funciones, cada una de ellas constituye un módulo y se caracteriza porque puede ser resuelto y probado de forma independiente. Cada módulo (cada función) debe recibir los datos que requiere, llevar a cabo la tarea que le compete y devolver (si la tarea así lo requiere) un resultado.
Se sabe que un módulo ha sido correctamente identificado cuando puede ser programado (resuelto) y probado de forma independiente. Un módulo nunca debe cambiar, borrar o alterar los datos de otro módulo, aunque un módulo puede (y generalmente lo hace) llamar (hacer uso) de otro u otros módulos. Además, un módulo debe garantizar que siempre, para los mismos datos, realizará la misma tarea y devolverá (si corresponde) el mismo resultado.
Una vez creado y probado un módulo, el mismo puede ser modificado internamente (por ejemplo para optimizar su rendimiento y/o hacer uso de nuevas características del lenguaje), pero su interfaz (su nombre y los datos que recibe), así como la tarea que realiza y el resultado que devuelve, deben ser siempre los mismos (para que los módulos que hacen uso de ese módulo puedan seguir haciendo su tarea correctamente).
Si la lógica dicta que un módulo debe ser modificado porque es necesario que reciba nuevos datos (lo que implica cambiar la interfaz) y/o la tarea que realiza debe ser modificada (aun cuando sea solo ligeramente), entonces, no se trata de una modificación a un módulo, sino de la creación de uno nuevo (con un nuevo nombre), porque si se hace una de esas modificaciones en el módulo original, todos los módulos que hacen uso del mismo, fallarían.
Para comenzar a familiarizarse con el lenguaje, adquirir práctica en la escritura de código y repasar los operadores y funciones matemáticas estudadas en C++, en esta sección se introducen los operadores y funciones matemáticas en JvaScript.
Los operadores matemáticos disponibles en JavaScript son:
| + | Suma |
| − | Resta |
| * | Multiplicación |
| / | División |
| % | Residuo (módulo) |
| ** | Potencia |
La única diferencia, con relación a C++, es el operador de potencia **, el cual permite calcular el resultado de elevar un número a una potencia, por ejemplo 2**3, devuelve 8, que es el resultado de elevar 2 al cubo (23).
En este capítulo, para escribir y ejecutar el código JavaScript, se hará uso de la calculadora JavaScript, así para calcular el valor de la siguiente operación:
| \[ 2+2 \] |
Se escribe la expresión en la calculadora y se la evalúa pulsando las teclas Shift+Enter (haga la prueba cambiando los valores). En los dispositivos móviles, para tener acceso a las teclas especiales (Shift, Ctrl, Alt, cursores, Esc, etc.,) deben instalar (desde Play Store) el teclado Unexpected Keyboard o Hacker's Keyboard.
Se procede de la misma forma en los siguientes casos:
| \[ 3\times4+5 \] |
| \[ 3.4+2.2-1.5 \] |
| \[ \text{residuo de } \dfrac{54}{7} \] |
| \[ 5.2^{3.1} \] |
Al igual que en C++, los operadores aritméticos se evalúan de acuerdo a su orden de prioridad: primero las potencias (**), luego la multiplicación y división (*, /) y finalmente la suma y la resta (+, -). Si dos o más operadores tienen el mismo orden de prioridad, se evalúan en secuencia de izquierda a derecha, excepto con la potencia, donde el orden se invierte, así la instrucción 3**4**5 es equivalente a 3**(4**5), es decir primero se calcula la potencia de la derecha y luego, con ese resultado, el de la izquierda.
Para alterar el orden de prioridad se emplean paréntesis: las expresiones escritas entre paréntesis se evalúan en primer lugar. Si existen paréntesis anidados (paréntesis dentro de otros paréntesis), primero se evalúan los paréntesis más internos.
Así, para evaluar la siguiente expresión:
| \[{3^2-3 \times 2+\dfrac{6}{2}\times 5} \over {3^2\times 2 - \dfrac{15}{5}\times 3}\] |
Se requieren 2 paréntesis: uno para el numerador y otro para el denominador, porque tanto el numerador como el denominador tienen operadores de menor prioridad que la división (sumas y restas) y en consecuencia, para que sean evaluadas antes que la división deben estar encerradas entre paréntesis:
Si el numerador sólo tiene operaciones de mayor o igual prioridad que la división (potencias, multiplicaciones o residuos), no se requieren paréntesis, porque primero se evaluarían las potencias y luego, de izquierda a derecha, las multiplicaciones y divisiones (o resíduos). Así dada la siguiente expresión:
| \[{2^3\times\dfrac{4}{3^2}\times{4}\times\dfrac{12}{3}} \over {3+\dfrac{9}{3}}-2\] |
Sólo se requieren paréntesis en el denominador, porque tiene operadores de menor prioridad (sumas y restas):
Si el denominador sólo tiene operaciones de mayor o igual nivel que la división, se puede prescindir de los paréntesis, sin embargo, como están en el denominador deben ser invertidas, es decir las multiplicaciones se convierten en divisiones y viceversa:
Así, para evaluar la siguiente expresión:
| \[{3\times 2^4\times\dfrac{8}{2}} \over {5\times\dfrac{3^2}{2}\times 4}\] |
Se escribe:
Pero, si bien el resultado es correcto, la expresión es difícil de leer, por lo que es fácil cometer errores. Por esa razón, para evitar errores, cuando el denominador tiene dos o más términos, se debe emplear paréntesis, sin importar el orden de prioridad de los operadores:
Igualmente, para evitar errores, si el numerador tiene dos o más términos, se recomienda emplear paréntesis, sin importar el orden de prioridad de los operadores:
Si ayuda a escribir una expresión más legible, se pueden emplear paréntesis adicionales tanto en el numerador como en el denominador:
No obstante, si se emplean paréntesis en exceso, la expresión resultante, en lugar de ser más legible resulta menos legible:
Por esa razón, solo se deben emplear paréntesis adicionales, cuando con ello se logra una expresión más legible.
Casi todo en JavaScript son objetos, incluidas las funciones y constantes matemáticas, que pertenecen al objeto Math.
Desde un punto de vista práctico, el que una función (o variable) sea parte de un objeto, significa que se debe escribir su nombre antes del nombre de la función (separadas por un punto).
Por ejemplo, para calcular el seno de 6.23 radianes, se escribe Math.sin(6.23):
Las funciones matemáticas disponibles en el objeto Math son:
| abs(x) | Valor absoluto de "x". |
| acos(x) | Arco coseno de "x". |
| acosh(x) | Arco coseno hiperbólico de "x". |
| asin(x) | Arco seno de "x" (resultado en radianes). |
| asinh(x) | Arco seno hiperbólico de "x". |
| atan(x) | Arco tangente de "x". |
| atanh(x) | Arco tangente hiperbólico de "x". |
| atan2(y,x) | Arco tangente del cociente de "y" entre "x". |
| cbrt(x) | Raíz cúbica de "x". |
| ceil(x) | Entero más cercano mayor o igual a "x". |
| clz32(x) | Número de ceros iniciales del entero "x" de 32 bits. |
| cos(x) | Coseno de "x". |
| cosh(x) | Coseno hiperbólico de "x". |
| exp(x) | Exponente de "x": \( e^x \). |
| expm1(x) | Devuelve \( e^x-1 \). |
| floor(x) | Entero más cercano menor o igual "x". |
| fround(x) | Devuelve el número real de simple precisión más cercano a "x". |
| hypot([x[,y[, ...]]]) | Raiz cuadrada de la suma de los cuadrados de "x", "y", ... |
| imul(x,y) | Multiplica los enteros de 32 bits "x" y "y". |
| log(x) | Logaritmo natural de "x": \( \ln(x)\). |
| log1p(x) | Logaritmo natural de "1+x": \(\ln(1+x)\). |
| log10(x) | Logaritmo en base 10 de "x": \(\log(x)\). |
| log2(x) | Logaritmo en base 2 de "x": \(\log_{{}_2}(x)\). |
| max([x[,[y[, ...]]]]) | Mayor de los números "x", "y", ... |
| min([x[,[y[, ...]]]]) | Menor de los números "x", "y", ... |
| pow(x,y) | "x" elevado a "y", (\(x^y\)), igual a x**y. |
| random() | Número aleatorio comprendido entre 0 y 1. |
| round(x) | Redondea "x" al entero más cercano. |
| sign(x) | Devuelve 1, si "x" es positivo, -1 si es negativo y 0 si es cero. |
| sin(x) | Seno del "x". |
| sinh(x) | Seno hiperbólico de "x". |
| sqrt(x) | Raíz cuadrada de "x". |
| tan(x) | Tangente del "x" ("x" en radianes). |
| tanh(x) | Tangente hiperbólica de "x". |
| trunc(x) | Parte entera de "x". |
Donde, casi todas las funciones tienen los mismos nombres que en C++ (excepto, claro, que deben ser escritas con "Math." por delante). Al igual que en C++, los ángulos en las funciones trigonométricas, deben estar en radianes.
Además de las funciones estándar, en la calculadora Javascript, se han añadido las siguientes funciones adicionales:
| cot(x) | Cotangente de "x". |
| coth(x) | Cotangente hiperbólica de "x". |
| csc(x) | Cosecante de "x". |
| csch(x) | Cosecante hiperbólica de "x". |
| even(x) | Verdadero si "x" es par. |
| factorial(x) | Factorial de "x". |
| frac(x) | Parte fraccionaria de "x". |
| log(b,x) | Logaritmo en base "b" de "x". |
| odd(x) | Verdadero si "x" es impar. |
| quot(x,y) | Cociente (parte entera) de "x/y". |
| sec(x) | Secante de "x". |
| sech(x) | Secante hiperbólica de "x". |
| sqr(x) | Cuadrado de "x" (x2). |
| toDeg(x) | Convierte "x" de radianes a grados. |
| toRad(x) | Convierte "x" de grados a radianes. |
| nthroot(x,n) | Raíz enésima (n) de "x". |
En el objeto Math se encuentran también las siguientes constantes:
| E | Número de Euler. |
| LN2 | Logaritmo natural de 2. |
| LN10 | Logaritmo natural de 10. |
| LOG2E | Logaritmo en base 2 del número de Euler. |
| LOG10E | Logaritmo en base 10 del número de Euler. |
| PI | Número pi. |
| SQRT1_2 | Raíz cuadrada de 1/2. |
| SQRT2 | Raíz cuadrada de 2. |
Que, como son valores (datos), se escriben sin paréntesis al final.
Aunque no es una regla, sino una convención, los nombres de las constantes se escriben en mayúsculas, como en SQRT2, y si son nombres compuestos se separan con guiones bajos, como en MAX_INTEGER. Los nombres de las variables (incluido los nombres de las funciones) se escriben en minúsculas, como en floor y si son nombres compuestos, la segunda y subsiguientes palabras se escriben con mayúscula inicial, como en firstElementChild ("estilo camello"). Las clases se escriben con la letra inicial en mayúsculas, como en Math.
Además, Javascript (como C++) diferencia entre mayúsculas y minúsculas, por lo tanto, Math, MATH, MaTh, mATH, math, etc., son nombres diferentes.
Debido a que en un lenguaje es muy fácil olvidar los nombres, es conveniente contar con una ayuda memoria. En el caso de la calculadora, si se comienza a escribir unas letras y se pulsan las teclas Ctrl+Espacio, aparece una ayuda con los nombres que comienzan con esas letras:
Es conveniente acostumbrarse a emplear este procedimiento no sólo como una ayuda memoria, sino para acelerar la escritura de código y reducir los errores.
Empleando paréntesis y las funciones matemáticas de Javascript, se puede calcular el valor de prácticamente cualquier expresión matemática.
Por ejemplo, para calcular el valor de la siguiente expresión matemática:
| \[\sqrt{{\sin(4.5)-\cos(1.2)}\over{\tan(2.3)}}\] |
Se escribe en la calculadora:
Y para calcular el valor de las siguiente expresión:
| \[\Big({\sin(1.2)+\cos(3.1)+\tan(0.7)}\Big)^{0.32}\] |
Se escribe:
En la calculadora, como ocurre en la mayoría de los editores, para deshacer la última acción se pulsan las teclas Ctrl+Z. Si bien es posible copiar y pegar en la forma estándar (Ctrl+C y Ctrl+V o Ctrl+Arrastrar con el mouse) es más eficiente recuperar instrucciones anteriores pulsando las teclas Ctrl+Arriba y las teclas Ctrl+Abajo para instrucciones posteriores.
Por ejemplo para calcular los cosenos de 5, 7, 10, 15 y 25 radianes, se procede de la siguiente forma:
Se recomienda emplear el anterior procedimiento siempre que sea posible. Así, para calcular el valor de las siguientes expresiones (que sólo difieren en dos signos):
| \[\sqrt{{3+4^{1.2}+6^{3.2}}\over{\text{e}^{6.5}+\cos(6.7)}}\] \[\sqrt{{3-4^{1.2}+6^{3.2}}\over{\text{e}^{6.5}-\cos(6.7)}}\] |
Se procede de la siguiente manera:
Resuelva los siguientes ejercicios para adquirir práctica en la escritura de código y el manejo de la calculadora y al mismo tiempo, memorizar los operadores y los nombres de algunas de las funciones.
Las variables en programación, al igual que en álgebra, son símbolos que representan algún tipo de información. En JavaScript, en particular, las variables pueden representar (hacer referencia) a todos los tipos de datos disponibles en el lenguaje. A diferencia de C/C++, las variables en JavaScript no tienen un tipo de dato fijo sino que toman su tipo del valor que se les asigna.
Los nombres de las variables tienen el denominativo general de identificadores y en la mayoría de los lenguajes de programación están conformadas por letras, números, guiones bajos (_) y el símbolo de dólar ($), siendo el primer carácter una letra, un guión bajo (_) o el símbolo $, pero, en JavaScript el primer carácter puede ser una vocal acentuada, eñes, letras griegas y en general cualquiera de los cientos de caracteres Unicode que tienen la propiedad Id_Start. El resto del nombre puede contener cualquiera de los caracteres del conjunto Unicode (más amplio) con la propiedad ID_Continue.
A diferencia de C/C++, JavaScript es un lenguaje interpretado, es decir que ejecuta las instrucciones inmediatamente a medida que las lee. Esta característica confiere gran flexibilidad, pero, en contrapartida, hace que sea más susceptible a los errores.
Para crear (declarar) variables en JavaScript se emplean las palabras reservadas var, let y const. La palabra var (actualmente en desuso) permite crear variables con un ámbito global (válidas en en el entorno y en los subentornos donde es declarada). Por otra perte let y const crean variables válidas únicamente en en el entorno en que son declaradas, además (let y const) no permiten que una variable vuelva a ser declarada en el mismo entorno, algo que evita los errores que se producen cuando (por error) una variable vuelve a ser declarada (algo que permite var y que es una de las razones por las que está en desuso).
Aunque su nombre sugiere lo contrario, las constantes (const) son igualmente variables, sólo que su valor no puede ser modificado, razón por la cual se conocen también como variables inmutables. Son el tipo más utilizado en los programas, porque usualmente no se quiere que el valor asignado a una variable sea modificado en el programa.
Una variable (declarada con let) puede ser sólo creada (declarada sin asignarle ningún valor) o creada e inicializada (declarada con un valor inicial). Las variables inmutables (const) por su naturaleza, siempre deben ser declarada e inicializadas (pues su valor no puede ser modificado).
Por ejemplo, para crear las variables "a", "b", "c", "d" y "e", sin inicalizarlas, se escribe:
Como solo son declaradas (no inicializadas), JavaScript le asigna el valor undefined (indefinido):
Observe que, al igual que en C/C++, las variables pueden ser declaradas una por una, como ocurre con las variables a y b, o dos o más al mismo tiempo (separándolas con comas) como ocurre con las variables c, d y e.
Observe también que, al igual que en C/C++, al final de cada instrucción se debe escribir un punto y coma (;). En realidad, en JavaScript, el punto y coma sólo es necesario si la instrucción no termina con un salto de línea, no obstante, si la siguiente línea comienza con un paréntesis u otro símbolo de agrupación u operador, se produce un error. Por esa razón se recomienda escribir siempre un punto y coma al final de cada instrucción. En la calculadora JavaScript, el punto y es obligatorio , excepto en la última línea, donde tiene un significado especial: Si se escribe, no se muestra el resultado de la última instrucción; Si no se escribe, se muestra el resultado de la última instrucción.
En el ejemplo se ha empleado también la instrucción print. Esta instrucción imprime (en la calculadora) el resultado de la expresión que se escribe entre los paréntesis. Se emplea en este ejemplo para imprimir el valor de las cinco variables a la vez. Si sólo se quiere imprimir el valor de una variable y esa variable se encuentra en la última línea (o es la única instrucción) simplemente se escribe su nombre, por ejemplo, para imprimir el valor de la variable "b", simplemente se escribe b:
Igualmente, se emplea print, cuando el valor a imprimir no es la última de las instrucciones, como en el siguiente ejemplo:
El equivalente (más avanzado) a print, en la consola de los navegadores y otras herramientas de desarrollo, es console.log.
Para asignar un valor a una variable se emplea (al igual que en C/C++) el operador de asignación: =, que tiene la siguiente sintaxis:
Es decir que la sentencia de asignación puede estar precedida (cuando se crean variables) por let o const. Si la variable fue creada previamente con let, para asignarle un nuevo valor, se escribe directamente el nombre de la variable (sin let) porque si se emplea let, se estaría volviendo a declarar la misma variable (algo que no está permitido en JavaScript).
Por ejemplo, con las siguientes instrucciones se crean las variables "x", "y" y "z" con los valores 4, 5 y 7.213×106. Luego en la siguiente celda se cambian esos valores a 10, 20 y 5.3×10-3:
Cuando una variable recibe un valor, asume el tipo de dato del valor. Así, en este caso, las variables "x", "y" y "z" son de tipo number (pues se les ha asignado números). El tipo de dato de una variable se obtenido con typeof:
Sin embargo, en JavaScript (a diferencia de C++) el tipado es dinámico. Si la variable recibe otro valor, cambia su tipo al del valor que recibe.
Con las variables se pueden llevar a cabo las mismas operaciones que con los tipos de datos que guardan, así, con "x", "y" y "z" (que son números) se pueden realizar todas las operaciones estudiadas previamente, por ejemplo, se puede calcular la hipotenusa de "x" y "y":
Que puede ser calculado de manera más sencilla con la función hypot:
Cuando se asigna a una variable un dato de tipo texto, el tipo de dato de la variable cambia a string, como se puede ver en el siguiente ejemplo:
Como se puede ver, las cadenas se crean simplemente escribiendo el texto entre comillas (al igual que en C++), pero también se pueden emplear apóstrofos (comillas simples).
Las cadenas se pueden concatenar (unir) con otras cadenas (u otros valores que son convertidos automáticamente en cadenas) empleando el operador de suma (+), sin embargo, resulta más claro y sencillo emplear plantillas literales, las que se crean escribiendo la cadena entre tildes invertidas (`...`) y en la cual se pueden insertar instrucciones JavaScript escribiéndolas dentro de ${}. Las instruccioes JavaScript escritss en una plantilla literal, son evaluadas, transformadas en texto e insertadas en esa posición en el texto resultante.
Así, en el siguiente ejemplo se concatenan dos catenas (con el operador de suma) y luego se obtienen los mismos resultados con plantillas literales:
Observe que al concatenar las cadenas se ha añadido un espacio (' ') para separar las cadenas. Igualmente, en las plantillas literales, se ha dejado un espacio en blanco entre las cadenas.
Si a una variable se asigna un valor booleano (true o false) el tipo de dato de la variable cambia a boolean, como se pued ver en el siguiente ejemplo:
JavaScript tiene los mismos operadores relacionales (>, <, >=, <=, ==, !=) y lógicos (&&, ||, !) que C++. Existen algunas diferencias que serán estudiadas posteriormente, pero por el momento es suficiente saber que, en JavaScript, se pueden construir las mismas expresiones lógicas que en C++.
Finalmente, si se asigna a una variable un array su tipo cambia a object, no a array como se esperaría.:
Como se puede ver, para crear un array en JavaScript, simplemente se escriben los elemenotos del array (separados con comas) ente corchetes.
El tipo de dato es object), porque en JavaScript, los array (así como otros datos estructurados) se crean a partir de clases y lo qu se crea a partir de una clase siempre es un objeto. Para determinar el tipo de objeto se puede recuperar el nombre del constructor del objeto:
En JavaScript, los elementos de un arreglo, se manipulan igual que en C++, es decir se accede a sus elementos por su índice (por su posición), siendo el primer índice 0. Por ejemplo, en la siguiente instrucción, se calcula la raíz cúbica de la suma del primer, tercer y quinto elementos de "v1":
En JavaScript, a diferencia de C++, los arreglos son dinámicos, es decir que su tamaño (el número de elementos que tiene) puede ser modificado en cualquier momento, lo que es de mucha utilidad cuando se elaboran programas de propósito general, además (a diferencia de C++) un arreglo puede tener diferentes tipos de elementos:
Los arreglos tienen varios métodos que serán estudiados posteriormente. Por el momento es suficiente saber como se declaran (crean) y como se pueden utilizar sus elementos.