Métodos condicionales 1

En este capítulo se repasan los operadores relacionales, los operadores lógicos, las estructuras condicionales y se emplean en la resolución de problemas que implican la toma de decisiones. Las soluciones se implementan empleando las clases de la programación orientada a objetos.

Operadores relacionales

Los operadores relacionales son empleados en la escritura de condiciones en programación. Una condición es toda sentencia de la cual se puede determinar su veracidad (true) o falsedad (false).

Los operadores relacionales comparan dos valores (escritos a ambos lados del operador) y devuelven siempre un valor booleano (true o false). JavaScript cuenta con los siguientes operadores relacionales:

Operadores Relacionales
OperadorDescripción
==Igual a
===Igual y del mismo tipo que
!=Diferente de
!==Diferente o de otro tipo que
>Mayor a
<Menor a
>=Mayor o igual a
<=Menor o igual a

Que tienen la misma sintaxis y semántica que en C/C++, sólo que, por defecto, JavaScript realiza automáticamente las conversiones de tipos que sean necesarias, antes de proceder a comparar los valores.

Por ejemplo, se pueden comparar texto con números:

"50.34">5.554
30.45<"3.43"
12>="15"
"23"<=64
77.2=="77.2"

En estas comparaciones, JavaScript, convierte primero el texto en números y luego compara los valores convertidos. No obstante, no es una buena práctica de programación combinar diferentes tipos de datos en una expresión, por lo que se aconseja no emplear esta forma frecuentemente.

La diferencia entre los operadores == y != y los operadores === y !==, radica en que los últimos no realizan ningun tipo de conversión, lo que es más seguro desde el punto de vista de programación, razón por la cual se recomienda su uso.

Por ejemplo, en las siguientes comparaciones, se obtienen resultados distintos con los dos tipos de operadores:

"23" == 23
"23" === 23
"68.5" != 68.5
"68.5" !== 68.5

Operadores lógicos

Los operadores lógicos comparan valores booleanos (o expresiones que pueden ser convertidas o interpretadas como booleanos). Conjuntamente los operadores relacionales, permiten escribir expresiones lógicas complejas.

JavaScript cuenta con los siguientes operadores lógicos:

Operadores Lógicos
OperadorDescripción
!Negación
&&Y lógico
||O lógico

Estos operadores tienen la misma sintaxis y semántica que en C/C++, así, el operador de negación: !, cambia el valor booleano de verdadero a falso y viceversa. El operador "Y": &&, devuelve verdadero sólo si los dos valores que compara son verdaderos, en cualquier otro caso devuelve falso. El operador "O" lógico: ||, devuelve falso sólo si los dos valores que compara son falsos, en cualquier otro caso devuelve verdadero.

JavaScript interpreta como valores falsos: el cero (0), el texto vacío (""), el valor nulo (null) y el valor undefined e interpreta como verdaderos cualquier texto no vacío y cualquier valor no nulo o indefinido.

Por ejemplo, las siguientes instrucciones devuelven la negación de algunos de estos valores:

!""
!"cadena"
!undefined
!null
!54.23

Evaluación en corto circuito

En JavaScript, al igual que en la mayoría de los lenguajes de programación, los operadores lógicos || e && se evalúan en cortocircuito, esto es, si con el primer valor se puede determinar, sin lugar a dudas, el resultado de la expresión, entonces el resultado es devuelto directamente, sin evaluar (sin tomar en cuenta) el valor restante.

En el caso del operador &&, se sabe que el resultado es falso si el primer valor es falso (porque falso && cualquier otro valor es siempre falso). En el caso del operador ||, se sabe que el resultado es verdadero si el primer valor es verdadero (porque verdadero || cualquier otro valor es siempre verdadero). Tal como se puede comprobar en los siguientes ejemplos, donde, aunque los segundos valores son en realidad erróneos (son variables y/o funciones inexistentes) no generan ningún error, porque el resultado de las expresiones se determinan directamente en base al primer primer término:

false && cos(3.2)
false && miVariable
true || tangente(6.43)
true || otraVariable

A diferencia de C/C++, en JavaScript, el resultado de un operador lógico no siempre es un valor booleano (true/false) sino el valor con el cual se determina la veracidad o falsedad de la expresión.

Así, el operador "Y" (&&) devuelve el primer término, si el mismo equivale a falso y el segundo en caso contrario, mientras que el operador "O" (||) devuelve el primer término si es equivalente a verdadero y el segundo en caso contrario. Tal como se puede ver en los siguientes ejemplos:

"" && 3 > 2
undefined && true
null && "Hola"
Math.sin(0) && Math.cos(5.32)
Math.cos(0) || true
"JavaScript" || false
"Aceptado" || "Rechazado"
Math.sqrt(25) || Math.cbrt(27)

Y las siguientes devuelven el segundo valor, pues con el primero no es posible determinar la veracidad o falsedad de la expresión:

true && "Resultado"
"Primero" && "Segundo"
1 && Math.sin(5.3)
false || "Resultado"
undefined || "Valor por defecto"
"" || "Rechazado"
0 || 2**5
45<23 || Math.sqrt(2)

Clases

Como se dijo previamente, las clases son los planos en base a los cuales se construyen los objetos o las industrias que fabrican los objetos (instancias de la clase).

En JavaScript, una clase puede ser creada en diferentes formas, sin embargo, formalmente, se crea empleando la palabra reservada class, de acuerdo a la siguiente sintaxis:

class nombre_de_la_clase { ... constructor(...) { } ... métodos getter y setter (dinámicos y estáticos) ... propiedades y métodos dinámicos (públicos y privados) ... propiedades y métodos estáticos (públicos y privados) ... bloques de inicialización estáticos ... }

Todos los elementos de una clase (los elementos mostrados en la sintaxis) son opcionales. Así, es posible crear una clase sin ningún elemento (una clase vacía):

class Vacio {
};

Y, aunque es una clase vacía, se pueden crear objetos (instancias) de esa clase.

Para crear un objeto (una instancia) de una clase se emplea la palabra reservada new, de acuerdo a la siguientes sintaxis:


var|let|const variable_objeto = new nombre_de_la_clase(valores_iniciales);

Así, para crear un objeto ('obj1') de la clase Vacio se escribe:

var obj1 = new Vacio();
obj1

Como se puede ver, en JavaScript un objeto se representa por llaves. Como en este caso "obj1" es un objeto vacío, las llaves están vacías.

Cada uno de los objetos que se crean a partir de una clase son únicos, aunque tengan los mismos datos, así por ejemplo, si se crea otro objeto vacío:

var obj2 = new Vacio();
obj2

Y se compara con el objeto creado previamente:

obj1 == obj2

El resultado es falso, porque aunque ambos son objetos vacíos de la misma clase, cada uno tiene su propia dirección de memoria y cuando se comparan objetos, lo que se compara es esa dirección de memoria.

Una vez creado un objeto de una clase, es posible (en JavaScript) añadirle propiedades y métodos. Por ejemplo en las siguientes instrucciones se añaden las propiedades "r=2.3" y "s=4.1" al objeto "obj1" y las propiedades "x=5.2" y "y=7.1" al objeto "obj2":

obj1.r = 2.3; obj1.s = 4.1; obj1
obj2.x = 5.2; obj2.y = 7.1; obj2

Y como cada objeto es independiente (aunque sean de la misma clase) las propiedades añadidas a un objeto, no afectan al otro.

Debido a que no se pueden crear dos o más clases con el mismo nombre, cuando se intenta modificar una clase (en la calculadora JavaScript) se produce un error.

Cuando se programa (cuando se codifica) casi siempre es necesario corregir o modificar el progrma y como una clase estándar no puede ser modificada, las clases (en la calculadora JavaScript) se crearan como clases anónimas de acuerdo a la siguiente sintaxis.

var nombre_de_la_clase = class { ... propiedades y métodos ... };

Por supuesto, una clase vacía no es de utilidad práctica. Para que una clase sea de utilidad práctica debe contar con algunas propiedades y métodos.

Por ejemplo, se puede crear la clase "Persona", con las propiedades "nombres" (valor por defecto "Carlos") y "apellidos" (valor por defecto "Pérez") y el método "nombreCompleto", que devuelva el nombre completo de la persona:

var Persona = class { nombres = "Carlos"; apellidos = "Perez"; nombreCompleto() { return `${this.nombres} ${this.apellidos}`; } };

Observe que en el método "nombre_completo", para acceder a las propiedades del objeto, se escribe this delante del nombre de las propiedades. Como ya se explicó previamente, this es la variable en la que JavaScript recibe (automáticamente) el objeto desde el cual se ha llamado al método.

Creando un objeto de esta clase ("persona1") y llamando al método "nombreCompleto" se obtiene:

var persona1 = new Persona()
persona1.nombreCompleto()

Asignando a "persona1" otros nombres y apellidos y llamando al método "nombreCompleto", se obtiene:

persona1.nombres = "Carlos Antonio"; persona1.apellidos = "Resini Bejarano"; persona1.nombreCompleto()

El constructor

No es muy útil crear objetos que tengan propiedades con los mismos valores (como se ha hecho hasta ahora). Por el contrario, en la práctica, las propiedades de los objetos (el estado de los objetos) son casi siempre diferentes.

Para crear un objetos donde sea posible asignar valores diferentes a sus propiedades, se debe programar el constructor de la clase.

El constructor es un método especial (una función) que se ejecuta automáticamente cuando se crea una instancia de la clase (cuando se crea un objeto) y es empleado para asignar valores iniciales a las propiedades del objeto que está siendo creado, así como realizar algunas validaciones y ejecutar los procedimientos iniciales que sean necesarios para dejar el objeto listo para su uso.

Así, en el siguiente ejemplo, se crea la clase "Persona" que, al momento de crear el objeto, permite asignar los nombres, apellidos y cédula de identidad (ci) del objeto. Además, al igual que en los ejemplos anteriores la clase cuenta con el método "nombreCompleto", sólo que ahora es creado con la palabra get por delante. Los métodos creados de esta manera se conocen como métodos getter y se caracterizan porque sólo devuelven un resultado, no reciben ningún dato y son llamados como se llama a una propiedad, es decir escribiendo únicamente el nombre (sin los paréntesis).

var Persona = class { constructor(nombres, apellidos, ci) { this.nombres = nombres; this.apellidos = apellidos; this.ci = ci; } get nombreCompleto() { return `${this.nombres} ${this.apellidos}`; } }

A partir de este ejemplo, si un método no recibe ningún dato y sólo devuelve un resultado, debe ser declarado como un método getter.

Ahora, con esta clase y gracias a su constructor, se crean dos objetos ("p1" y "p2") con valores diferentes para cada uno de ellos:

var p1 = new Persona("Juan Carlos", "Carranza Siles", 23821245); print(p1.nombreCompleto); p1.ci
var p2 = new Persona("Yolanda", "Vidal Argandoña", 75343235); print(p2.nombreCompleto); p2.ci

Herencia

En la programación orientada a objetos (POO), una clase puede (y generalmente lo hace) heredar las propiedades y métodos de otra clase. De hecho (por defecto) todas las clases en JavaScript y en consecuencia, todos los objetos, heredan automáticamente de la clase predefinida Object.

Para que explícitamente una clase herede de otra (extienda a otra) se emplea la palabra reservada extends, de acuerdo al siguiente sintaxis

class nombre_clase_extendida extends nombre_clase_base { ... }

Cuando la clase padre (la clase base) tiene un constructor y la clase hija declara nuevas propiedades, debe tener su propio constructor y en el mismo, lo primero que se debe hacer es llamar al constructor de la clase padre. Para llamar al constructor de la clase padre, se emplea el método especial super (super permite, también, llamar a los métodos de la clase padre, con la sintaxis: super.método()).

Por ejemplo, en la siguiente instrucción se crea la clase Estudiante, que hereda de la clase Persona (extiende la clase Persona) añadiendo una nueva propiedad: "carrera":

var Estudiante = class extends Persona { constructor(nombres, apellidos, ci, carrera) { super(nombres, apellidos, ci); this.carrera = carrera; } };

Con el cual se puede crear, por ejemplo, el objeto "estudiante1":

var estudiante1 = new Estudiante("Alberto", "Sandi Carballo", 32883235, "Ingeniería de Sistemas");

Y desde este objeto, se puede llamar tanto a los métodos y propiedades del padre ("nombreCompleto" y "ci") como a su propiedad ("carrera"):

print(estudiante1.nombreCompleto); print(estudiante1.ci); estudiante1.carrera

Como se dijo, todas las clases en JavaScript heredan, automáticamente, de la clase Object, por lo tanto, todos los objetos heredan los métodos dinámicos de esta clase.

De los métodos heredados de Object, son de particular interés los métodos valueOf y toString. El método valueOf (empleando ya en el capítulo previo) es llamado automáticamente por JavaScript, cuando un objeto forma parte de una expresión. Si es posible, JavaScript emplea el valor devuelto por valueOf para realizar las operaciones.

Por defecto, el método valueOf de Object, simplemente devuelve el objeto desde el cual es llamado, lo que no es de utilidad práctica. Por ese motivo las clases que lo heredan (todas las clases) deben sobreescribirlo, para que devuelva un valor que sea de utilidad práctica en las expresiones en las cuales aparecen sus objetos.

Igualmente, el método toString, es llamado automáticamente por JavaScript cuando necesita un texto que represente al objeto. Por defecto el método toString, de la clase Object, devuelve el texto "[object Object]", que no es de utilidad práctica. Por esa razón, este método también debe ser redefinido (reescrito) en las clases que lo heredan (en todas las clases) para que devuelva un valor (un string) que represente adecuadamente al objeto.

Por ejemplo, se pueden sobreescribir estos métodos en la clase Estudiante, de manera que valueOf devuelva (solo a manera de ejemplo) la carrera del estudiante y que toString devuelva su nombre completo:

var Estudiante = class extends Persona { constructor(nombres, apellidos, ci, carrera) { super(nombres, apellidos, ci); this.carrera = carrera; } valueOf() { return this.carrera; } toString() { return this.nombreCompleto; } };

Ahora, si se crea un objeto de esta clase:

estudiante2 = new Estudiante("Jorge Antonio", "Gomez Cervantes", 30284772, "Ingeniería de Software");

Y se emplea en una expresión, se obtiene:

"El estudiante está en la carrera de: "+estudiante2

Porque, JavaScript, al tratarse de una expresión llama automáticamente al método valueOf, con lo que el nombre del objeto es reemplazado por la carrera del estudiante.

Si se requiere la cadena (string) del objeto, como cuando el objeto forma parte de una plantilla literal:

`El nombre completo de la persona es: ${estudiante2}`

JavaScript llama automáticamente al método toString, con lo que el objeto es reemplazado con el nombre completo del estudiante.

Expresiones condicionales

Las expresiones condicionales son aquellas que involucran operadores aritméticos, relacionales y/o lógicos y que devuelven un valor booleano o un valor que puede ser interpretado como booleano.

Algunos problemas condicionales simples pueden ser resueltos empleando dírectamente expresiones condicionales. Por ejemplo, para dertermnar si un número es par (o impar) es suficiente verificar que el residuo de su división entre cero, sea cero.

Para resolver un problema simple como este (empleando una clase) se tienen por lo menos 3 opciones:

  1. Crear una clase independiente, con una propiedad de tipo numérica, sobre la que trabajan los métodos de la clase. Esta es la opción más larga porque es necesario sobreescribir todos los métodos faltantes, tales como valueOf y toString.
  2. En lugar de sobreescribir todos los métodos, se crea una clase que hereda de otra, en este caso, al tratarse de una operación con números la clase padre más adecuada es Number. De esa manera sólo es necesario escribir los nuevos métodos.
  3. En lugar de crear una nueva clase, se modifica una existente, simplemente añadiendo los nuevos métodos (una vez más, como se trata de operaciones con números, la clase a modificar es Number). Esta es la opción más corta y práctica, pero también la menos aconsejabe y menos segura, porque se modifica una clase predefinida del lenguaje, lo que puede dar lugar a errores inesperados.

El código que resuelve el problema, con la primera opción (clase independiente), es:

var Número = class { constructor(número) { this.n = número; } get esPar() { return this.n%2===0; } get esImpar() { return this.n%2!==0; } }

La cual permite crear objetos de esta clase y determinar si son pares o impares. Por ejemplo, a continuación se crea el objeto "x" con el números 34 y se determina si es par e impar:

var x = new Número(34)
x.esPar
x.esImpar

Pero si se emplea el objeto en una expresión, por ejemplo si se le suma un número, o en una plantilla literal:

x+7
`El valor del número es ${x}`

JavaScript reemplaza (en ambos casos) el objeto "x" por la cadena "[object Object]".

En el primer caso (la suma), JavaScript llama primero a valueOf, pero como el resultado es un objeto (el objeto original), que no puede ser sumado, llama a toString (que devuelve "[object Object]"), entonces concatena (suma) esa cadena a "7" (es decir la cadena del número 7).

En el segundo caso, JavaScript llama a toString y reemplaza "[object Object]" en lugar de "${x}".

En consecuencia, es necesario sobreescribir los métodos valueOf y toString, de manera que devuelvan el número y el texto del número:

var Número = class { constructor(número) { this.n = número; } get esPar() { return this.n%2===0; } get esImpar() { return this.n%2!==0; } valueOf() { return this.n; } toString() { return this.n.toString(); } }

Donde los métodos getter "esPar" y "esImpar" siguen funcionando como antes, pero ahora, cuando el objeto aparece en una expresión es reemplazado por su valor numérico y cuando es empleado en una plantilla literal o en cualquier expresión que requiera un texto, es reemplazado por el número en formato de cadena:

y = new Número(27);
y.esPar
y.esImpar
y+15
`El valor de y es: ${y}`

El código que resuelve el problema con la segunda opción (clase heredada), es:

var Número2 = class extends Number { get esPar() { return this%2===0; } get esImpar() { return this%2!==0; } }

Note que la nueva clase no tiene un constructor propio, porque la clase heredada no añade ninguna propiedad. Por lo tanto la clase heredada emplea el constructor de la clase padre ("Number"), que simplemente recibe el número.

Tampoco es necesario sobreescribir los métodos valueOf y toString, porque son heredados de la clase Number y en consecuencia son los métodos correctos para trabajar con números. De hecho, la principal razón por la que no es necesario definir una nueva propiedad en la clase heredada, es porque el método valueOf de la clase Number devuelve el número (el valor primitivo).

Creando el objeto "z", de esta clase, se obtienen los resultados esperados:

var z = new Número2(71);
z.esPar
z.esImpar
z+12
`El valor de z es: ${z}`

Para la tercera opción, no es suficiente añadir el método a la propiedad prototype de la clase Number, como se ha hecho en los anteriores capítulos, porque de esa forma sólo es posible añadir métodos estándar, no métodos getter/setter. Para añadir métodos getter/setter se debe emplear el método estático defineProperty de la clase Object, de acuerdo a la siguiente sintaxis:

Object.defineProperty(objeto o clase, propiedad, { get() { ... }, set(valor) { ... }, enumerable: true/false, configurable: true/false })

Donde solo es imprescindible definir un método getter (get) o un método setter (set), el resto las propiedades son opcionales.

Por defecto enumerable y configurable son falsos, lo que implica que él o los métodos definidos no aparecen como propiedades de la clase (enumerable) y que no pueden ser modificados (configurable). Dado que, casi siempre, es necesario modificar o corregir el código, es prácticamente imprescindible (por lo menos en la calculadora Javascript) colocar la propiedad configurable en true.

Con el método defineProperty se puede añadir también una propiedad a la clase, de acuerdo a la siguiente sintaxis:

Object.defineProperty(objeto o clase, propiedad, { value: valor, writable: true/false, enumerable: true/false, configurable: true/false })

Donde sólo es necesario asignar el valor a la propiedad value. El resto de las campos son opcionales y por defecto tienen un valor igual a false, que, en el caso de writable, significa que el valor asignado a la propiedad no puede ser modificado.

Para definir dos o más métodos (o propiedades) al mismo tiempo, una mejor alternativa es el método estático defineProperties, que tiene la sintaxis:

Object.defineProperties(objeto o clase, { propiedad1/método1: { ... }, propiedad2/método2: { ... }, ... propiedadn/métodon: { ... } })

Donde, cada propiedad/método, puede tener todos los campos mostrados en defineProperty.

Como en este caso se quiere añadir dos métodos, la opción más adecuada es defineProperties:

Object.defineProperties(Number.prototype, { esPar: { get() { return this%2===0; }, configurable: true }, esImpar: { get() { return this%2!==0; }, configurable: true } });

Al tratarse de la clase estándar Number, no es imprescindible crear objetos de esa clase, pues los métodos pueden ser llamados directamente desde los números (como se vio en capítulos previos):

(124).esPar
(311).esImpar

Diagramas de flujo

A partir de este capítulo, algunos algoritmos serán presentados en forma de diagramas de flujo. Dichos diagramas han sido elaborados con la ayuda de la librería GoJS.

En los diagramas de flujo se emplearán las formas geométricas estándar. Así, el inicio y el fin se representan con nodos rectangulares de lados redondeados (píldoras):

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Start","text":"inicio","key":-1,"loc":"-299 -366"},{"category":"Start","text":"fin","key":-2,"loc":"-202 -366"}],"linkDataArray":[]}})

La entrada de datos y la salida de resultados, se representan, respectivamente, con un paralelogramo y un rectángulo de fondo ondulado:

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Input","text":"entrada","key":-3,"loc":"-119-369"},{"category":"Output","text":"salida","key":-5,"loc":"-21-366"}],"linkDataArray":[]}});

Para las condiciones (preguntas) se emplea un rombo:

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Conditional","text":"condición","key":-4,"loc":"-90-365"}],"linkDataArray":[]}})

El símbolo para las instrucciones (procesos, operaciones, comandos) es un rectángulo:

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Process","text":"proceso","key":-2,"loc":"-122-367"}],"linkDataArray":[]}})

Los módulos (subrutinas) se representan con un rectángulo con dos líneas verticales adicionales, a ambos lados:

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Procedure","text":"subrutina","key":-7,"loc":"-115-364"}],"linkDataArray":[]}})

Aunque no es propiamente un estándar (pero sí una forma ampliamente utilizada en la práctica) para representar la estructura for, se emplea un rectángulo de lados angulares:

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"For","text":"desde","key":-6,"loc":"-131-375"}],"linkDataArray":[]}})

Para conectar dos puntos separados del diagrama, se emplean círculos:

gojsGraph({divi, modelo:{"class":"go.GraphLinksModel","linkFromPortIdProperty":"fromPort","linkToPortIdProperty":"toPort","nodeDataArray":[{"category":"Connector","text":"...","key":-8,"loc":"-146-376"}],"linkDataArray":[]}})

Por ejemplo, el siguiente diagrama, corresponde al algoritmo para calcular (y devolver) el perímetro y área de un círculo de radio "r":

gojsGraph({divi, modelo:{ "class": "go.GraphLinksModel", "linkFromPortIdProperty": "fromPort", "linkToPortIdProperty": "toPort", "nodeDataArray": [ {"category":"Start", "text":"paCirculo", "key":-1, "loc":"-107 -374"},{"category":"Input", "text":"radio: r", "key":-3, "loc":"-107 -327"},{"category":"Process", "text":"p = 2*PI*r", "key":-2, "loc":"-107 -277"},{"category":"Process", "text":"a = PI*r**2", "key":-4, "loc":"-107 -226"},{"category":"Output", "text":"p, a", "key":-5, "loc":"-107 -169"},{"category":"Start", "text":"fin", "key":-6, "loc":"-107 -116"} ], "linkDataArray": [ {"from":-1, "to":-3, "fromPort":"B", "toPort":"T", "points":[-107,-358.7333213806152,-107,-348.7333213806152,-107,-348.7333213806152,-107,-351.2666786193848,-107,-351.2666786193848,-107,-341.2666786193848]},{"from":-3, "to":-2, "fromPort":"B", "toPort":"T", "points":[-107,-312.7333213806152,-107,-302.7333213806152,-107,-302.7333213806152,-107,-304.2666786193848,-107,-304.2666786193848,-107,-294.2666786193848]},{"from":-2, "to":-4, "fromPort":"B", "toPort":"T", "points":[-107,-259.7333213806152,-107,-249.73332138061522,-107,-249.73332138061522,-107,-253.26667861938478,-107,-253.26667861938478,-107,-243.26667861938478]},{"from":-4, "to":-5, "fromPort":"B", "toPort":"T", "points":[-107,-208.73332138061525,-107,-198.73332138061525,-107,-197.6722262064616,-107,-197.6722262064616,-107,-196.61113103230795,-107,-186.61113103230795]},{"from":-5, "to":-6, "fromPort":"B", "toPort":"T", "points":[-107,-156.31998565673828,-107,-146.31998565673828,-107,-143.79333213806154,-106.99999999999999,-143.79333213806154,-106.99999999999999,-141.26667861938478,-106.99999999999999,-131.26667861938478]} ]}})

Como se puede ver, para calcular el perímetro y área de un círculo, se debe recibir el radio del círculo (r), luego, con el radio recibido se calcula el perímetro (p) y el área (a). Finalmente, se devuelven el perímetro (p) y el área (a) calculados, con lo que el proceso concluye.

Las expresiones matemáticas en los diagramas de flujo, se escribirán empleando los operadores y funciones de JavaScript, pero sin Math en las funciones y constantes matemáticas (como se ha hecho en el ejemplo).

Una vez elaborado el diagrama de flujo, la codificación (el escribir el programa propiamente) es principalmente un proceso mecánico, pues la lógica, que es la secuencia de acciones que resuelven el problema, ya ha sido resuelta en el diagrama de flujo.

Así, el código correspondiente a este diagrama de flujo, implementado como una clase heredada, es:

var Círculo = class extends Number { get paCírculo() { const p = 2*Math.PI*this; const a = Math.PI*this**2; return {perímetro: p, área: a}; } }

Para devolver los dos resultados se ha empleado un objeto literal. Como se recordará, un objeto literal se crea encerrando las propiedades del objeto entre llaves. Cada propiedad se crea escribiendo su nombre y su valor. Las propiedades se separan con comas.

Creando un objeto de esta clase, con un radio igual a 2.54 y llamando al método paCirculo, se obtiene:

var c1 = new Círculo(2.54);
c1.paCírculo

Los diagramas de flujo, en GoJS, se crean como se muestra en el siguiente video, donde se elabora el diagrama de flujo para sumar dos números:

Además, cualquier acción puede ser deshecha (undo) con el atajo estándar Ctrl+Z y rehecha (redo) con el atajo estándar Ctrl+Y.

En los teléfonos y tabletas se trabaja de la misma forma, sólo que varias de las opciones, como: copiar (Copy), pegar (Paste), cortar (Cut), eliminar (Delete), deshacer (Undo), rehacer (Redo), etc., están disponibles a través del menú contextual que aparece cuando se hace una pulsación larga en uno de los elementos de la gráfica. Además, en los ejercicios, para evaluar la gráfica (con Shift+Enter) debe estar seleccionado el texto de un nodo (de cualquier nodo), para que aparezca el teclado y sea posible pulsar las teclas Shift+Enter.