La sintaxis de JavaScript es el conjunto de reglas que definen un programa JavaScript correctamente estructurado.
Los ejemplos a continuación utilizan la función de registro del objeto de consola presente en la mayoría de los navegadores para la salida de texto estándar .
La biblioteca estándar de JavaScript carece de una función oficial de salida de texto estándar (con la excepción de document.write
). Dado que JavaScript se utiliza principalmente para la creación de scripts del lado del cliente en los navegadores web modernos , y que casi todos los navegadores web proporcionan la función de alerta, alert
también se puede utilizar , pero no se utiliza habitualmente.
Brendan Eich resumió la ascendencia de la sintaxis en el primer párrafo de la especificación JavaScript 1.1 [1] [2] de la siguiente manera:
JavaScript toma prestada la mayor parte de su sintaxis de Java , pero también hereda de Awk y Perl , con cierta influencia indirecta de Self en su sistema de prototipos de objetos.
JavaScript distingue entre mayúsculas y minúsculas . Es habitual empezar el nombre de un constructor con una letra mayúscula y el nombre de una función o variable con una letra minúscula.
Ejemplo:
var a = 5 ; console . log ( a ); // 5 console . log ( A ); // lanza un ReferenceError: A no está definido
A diferencia de C , los espacios en blanco en el código fuente de JavaScript pueden afectar directamente la semántica . Los puntos y comas terminan las sentencias en JavaScript. Debido a la inserción automática de puntos y comas (ASI), algunas sentencias que están bien formadas cuando se analiza una nueva línea se considerarán completas, como si se hubiera insertado un punto y coma justo antes de la nueva línea. Algunas autoridades recomiendan proporcionar puntos y comas de finalización de sentencias de forma explícita, porque puede reducir los efectos no deseados de la inserción automática de puntos y comas. [3]
Hay dos problemas: cinco tokens pueden comenzar una declaración o ser la extensión de una declaración completa; y cinco producciones restringidas, donde no se permiten saltos de línea en ciertas posiciones, lo que potencialmente produce un análisis incorrecto.
Los cinco símbolos problemáticos son el paréntesis de apertura " (
", el corchete de apertura " [
", la barra " /
", el signo más " +
" y el signo menos " -
". De estos, el paréntesis de apertura es común en el patrón de expresión de función invocada inmediatamente , y el corchete de apertura aparece a veces, mientras que otras veces son bastante raras. Un ejemplo:
a = b + c ( d + e ) .foo () // Tratado como: // a = b + c(d + e).foo();
con la sugerencia de que la declaración precedente termine con punto y coma.
Algunos sugieren en cambio el uso de punto y coma inicial en las líneas que comienzan con ' (
' o ' [
', de modo que la línea no se una accidentalmente con la anterior. Esto se conoce como punto y coma defensivo y se recomienda especialmente, porque de lo contrario el código puede volverse ambiguo al reorganizarse. Por ejemplo:
a = b + c ;( d + e ) .foo () // Tratado como: // a = b + c; // (d + e).foo();
Los puntos y coma iniciales también se utilizan a veces al comienzo de las bibliotecas de JavaScript, en caso de que se agreguen a otra biblioteca que omite un punto y coma final, ya que esto puede generar ambigüedad en la declaración inicial.
Las cinco producciones restringidas son return
, throw
, break
, continue
, y post-incremento/decremento. En todos los casos, insertar punto y coma no soluciona el problema, pero aclara la sintaxis analizada, lo que hace que el error sea más fácil de detectar. return
y throw
toman un valor opcional, mientras que break
y continue
toman una etiqueta opcional. En todos los casos, el consejo es mantener el valor o la etiqueta en la misma línea que la declaración. Esto aparece con mayor frecuencia en la declaración de retorno, donde uno podría devolver un literal de objeto grande, que podría colocarse accidentalmente comenzando en una nueva línea. Para post-incremento/decremento, existe una posible ambigüedad con pre-incremento/decremento, y nuevamente se recomienda simplemente mantenerlos en la misma línea.
devuelve a + b ; // Devuelve indefinido. Se trata como: // return; // a + b; // Debe escribirse como: // return a + b;
La sintaxis de los comentarios es la misma que en C++ , Swift y muchos otros lenguajes.
// un comentario breve de una línea/* Este es un comentario largo de varias líneas sobre mi guión. Ojalá algún día sea genial. *//* Los comentarios /* no pueden estar anidados */ Error de sintaxis * /
Las variables en JavaScript estándar no tienen un tipo adjunto, por lo que cualquier valor (cada valor tiene un tipo) se puede almacenar en cualquier variable. A partir de ES6 , la sexta versión del lenguaje, las variables se podían declarar con var
para las variables con ámbito de función, y let
o const
que son para las variables de nivel de bloque . Antes de ES6, las variables solo se podían declarar con una var
declaración. Los valores asignados a las variables declaradas con const
no se pueden cambiar, pero sus propiedades sí. var
ya no se deben usar desde let
y const
son compatibles con los navegadores modernos. [4] El identificador de una variable debe comenzar con una letra, un guión bajo ( _
) o un signo de dólar ( $
), mientras que los caracteres posteriores también pueden ser dígitos ( 0-9
). JavaScript distingue entre mayúsculas y minúsculas, por lo que los caracteres en mayúsculas "A" a "Z" son diferentes de los caracteres en minúsculas "a" a "z".
A partir de JavaScript 1.5, se pueden utilizar letras ISO 8859-1 o Unicode (o \uXXXX
secuencias de escape Unicode) en identificadores. [5] En ciertas implementaciones de JavaScript, se puede utilizar el signo arroba (@) en un identificador, pero esto es contrario a las especificaciones y no se admite en implementaciones más nuevas. [ cita requerida ]
Las variables declaradas con var
tienen un alcance léxico a nivel de función , mientras que las que tienen let
o const
tienen un alcance a nivel de bloque . Dado que las declaraciones se procesan antes de que se ejecute cualquier código, se puede asignar una variable y usarla antes de declararla en el código. [6] Esto se conoce comoelevación , y es equivalente a que las variables sedeclaren hacia adelanteen la parte superior de la función o bloque.[7]
Con las instrucciones var
, let
, y const
, solo se eleva la declaración; las asignaciones no se elevan. Por lo tanto, una instrucción en el medio de la función es equivalente a una instrucción de declaración en la parte superior de la función y una instrucción de asignación en ese punto en el medio de la función. Esto significa que no se puede acceder a los valores antes de que se declaren; la referencia hacia adelante no es posible. Con el valor de una variable es hasta que se inicializa. No se puede acceder a las variables declaradas con o hasta que se hayan inicializado, por lo que hacer referencia a dichas variables antes provocará un error.var x = 1
var x
x = 1
var
undefined
let
const
Las declaraciones de función, que declaran una variable y le asignan una función, son similares a las declaraciones de variable, pero además de elevar la declaración, también elevan la asignación (como si la declaración completa apareciera en la parte superior de la función que la contiene) y, por lo tanto, también es posible la referencia hacia adelante: la ubicación de una declaración de función dentro de una función que la encierra es irrelevante. Esto es diferente de una expresión de función que se asigna a una variable en una declaración var
, let
o const
.
Así, por ejemplo,
var func = function () { .. } // solo se eleva la declaración function func () { .. } // se eleva la declaración y la asignación
El alcance de bloque se puede producir envolviendo todo el bloque en una función y luego ejecutándolo (esto se conoce como patrón de expresión de función invocada inmediatamente ) o declarando la variable usando la let
palabra clave.
Las variables declaradas fuera de un ámbito son globales . Si una variable se declara en un ámbito superior, los ámbitos secundarios pueden acceder a ella.
Cuando JavaScript intenta resolver un identificador, busca en el ámbito local. Si no encuentra este identificador, busca en el siguiente ámbito externo, y así sucesivamente a lo largo de la cadena de ámbitos hasta llegar al ámbito global donde residen las variables globales. Si sigue sin encontrarlo, JavaScript generará una ReferenceError
excepción.
Al asignar un identificador, JavaScript pasa por exactamente el mismo proceso para recuperar este identificador, excepto que si no se encuentra en el ámbito global , creará la "variable" en el ámbito donde fue creada. [8] Como consecuencia, una variable nunca declarada será global, si se asigna. Declarar una variable (con la palabra clave var
) en el ámbito global (es decir, fuera de cualquier cuerpo de función (o bloque en el caso de let/const)), asignar un identificador nunca declarado o agregar una propiedad al objeto global (generalmente window ) también creará una nueva variable global.
Tenga en cuenta que el modo estricto de JavaScript prohíbe la asignación de una variable no declarada, lo que evita la contaminación del espacio de nombres global.
A continuación se muestran algunos ejemplos de declaraciones de variables y su alcance:
var x1 = 0 ; // Una variable global, porque no está en ninguna función let x2 = 0 ; // También global, esta vez porque no está en ningún bloque función f () { var z = 'zorros' , r = 'pájaros' ; // 2 variables locales m = 'peces' ; // global, porque no se declaró en ningún lugar antes función hija () { var r = 'monos' ; // Esta variable es local y no afecta a los "pájaros" r de la función padre. z = 'pingüinos' ; // Cierre: La función hija puede acceder a las variables de la función padre. } veinte = 20 ; // Esta variable se declara en la siguiente línea, pero se puede utilizar en cualquier parte de la función, incluso antes, como aquí var veinte ; niño (); devolver x1 + x2 ; // Podemos usar x1 y x2 aquí, porque son globales } f ();console.log ( z ); // Esta línea generará una excepción ReferenceError , porque el valor de z ya no está disponible
para ( let i = 0 ; i < 10 ; i ++ ) console.log ( i ) ; console.log ( i ); // lanza un ReferenceError : i no está definido
for ( const i = 0 ; i < 10 ; i ++ ) console . log ( i ); // lanza un TypeError: Asignación a variable constante for ( const i of [ 1 , 2 , 3 ]) console . log ( i ); //no lanzará una excepción. i no se reasigna sino que se vuelve a crear en cada iteración const pi ; // arroja un SyntaxError: Falta inicializador en la declaración const
El lenguaje JavaScript proporciona seis tipos de datos primitivos :
Algunos de los tipos de datos primitivos también proporcionan un conjunto de valores con nombre que representan la extensión de los límites del tipo. Estos valores con nombre se describen en las secciones correspondientes a continuación.
El valor "undefined" se asigna a todas las variables no inicializadas y también se devuelve cuando se comprueban propiedades de objetos que no existen. En un contexto booleano, el valor "undefined" se considera un valor falso.
Nota: undefined se considera un tipo primitivo genuino. A menos que se convierta explícitamente, el valor undefined puede comportarse de manera inesperada en comparación con otros tipos que evalúan como falsos en un contexto lógico.
let test ; // variable declarada, pero no definida, ... // ... establecida en valor indefinido const testObj = {}; console . log ( test ); // variable de prueba existe, pero valor no ... // ... definido, muestra indefinido console . log ( testObj . myProp ); // testObj existe, propiedad no, ... // ... muestra indefinido console . log ( undefined == null ); // tipo no aplicado durante la comprobación, muestra verdadero console . log ( undefined === null ); // tipo aplicado durante la comprobación, muestra falso
Nota: No existe un literal de lenguaje incorporado para undefined. Por lo tanto, no es una forma infalible de verificar si una variable está indefinida, porque en versiones anteriores a ECMAScript 5, es legal que alguien escriba . Un enfoque más sólido es comparar usando .(x === undefined)
var undefined = "I'm defined now";
(typeof x === 'undefined')
Funciones como ésta no funcionarán como se espera:
function isUndefined ( x ) { sea u ; return x === u ; } // así... function isUndefined ( x ) { return x === void 0 ; } // ... o esa segunda function isUndefined ( x ) { return ( typeof x ) === "undefined" ; } // ... o esa tercera
Aquí, al llamar isUndefined(my_var)
se genera un ReferenceError si my_var es un identificador desconocido, mientras que no lo hace.typeof my_var === 'undefined'
Los números se representan en binario como dobles de punto flotante IEEE 754. Aunque este formato proporciona una precisión de casi 16 dígitos significativos , no siempre puede representar con exactitud los números reales, incluidas las fracciones.
Esto se convierte en un problema al comparar o formatear números. Por ejemplo:
console.log ( 0.2 + 0.1 === 0.3 ) ; // muestra falso console.log ( 0.94 - 0.01 ) ; // muestra 0.9299999999999999
Como resultado, se debe utilizar una rutina como el método toFixed() para redondear números siempre que se formatean para la salida.
Los números pueden especificarse en cualquiera de estas notaciones:
345 ; // un "entero", aunque solo hay un tipo numérico en JavaScript 34.5 ; // un número de punto flotante 3.45e2 ; // otro de punto flotante, equivalente a 345 0b1011 ; // un entero binario igual a 11 0o377 ; // un entero octal igual a 255 0xFF ; // un entero hexadecimal igual a 255, dígitos representados por las ... // ... letras AF pueden ser mayúsculas o minúsculas
También hay un separador numérico, _ (el guión bajo), introducido en ES2021:
// Nota: La sintaxis de Wikipedia aún no admite separadores numéricos 1 _000_000_000 ; // Se utiliza con números grandes 1 _000_000 .5 ; // Admite decimales 1 _000e1_000 ; // Admite exponentes // Soporte para binarios, octales y hexadecimales 0b0000 _0000_0101_1011 ; 0o0001 _3520_0237_1327 ; 0xFFFF _FFFF_FFFF_FFFE ;// Pero no puedes usarlos al lado de una parte de número que no sea un dígito, o al principio o al final _12 ; // La variable no está definida (el guión bajo la convierte en un identificador de variable) 12 _ ; // Error de sintaxis (no puede estar al final de los números) 12 _ .0 ; // Error de sintaxis (no tiene sentido poner un separador al lado del punto decimal) 12. _0 ; // Error de sintaxis 12 e_6 ; // Error de sintaxis (al lado de "e", un no-dígito. No tiene sentido poner un separador al principio) 1000 ____0000 ; // Error de sintaxis (al lado de "_", un no-dígito. Solo se permite 1 separador a la vez
Las extensiones +∞ , −∞ y NaN (Not a Number) del tipo número se pueden obtener mediante dos expresiones de programa:
Infinito ; // infinito positivo (el negativo se obtiene con -Infinity, por ejemplo) NaN ; // El valor No-Un-Número, también devuelto como un error en... // ... conversiones de cadena a número
Infinito y NaN son números:
typeof Infinity ; // devuelve "número" typeof NaN ; // devuelve "número"
Estos tres valores especiales corresponden y se comportan como los describe el IEEE-754 .
El constructor Number (usado como función), o un unario + o -, se puede utilizar para realizar una conversión numérica explícita:
const miCadena = "123.456" ; const miNumero1 = Número ( miCadena ); const miNumero2 = + miCadena ;
Cuando se utiliza como constructor, se crea un objeto contenedor numérico (aunque es de poca utilidad):
const myNumericWrapper = nuevo Número ( 123.456 );
Sin embargo, NaN no es igual a sí mismo:
constante nan = NaN ; consola . iniciar sesión ( NaN == NaN ); // consola falsa . iniciar sesión ( NaN === NaN ); // consola falsa . iniciar sesión ( NaN ! == NaN ); // verdadera consola . iniciar sesión ( nan !== nan ); // verdadero // Puede utilizar los métodos isNaN para comprobar si hay NaN console.log(isNaN ( " convertido a NaN " ) ) ; // verdadero console.log ( isNaN ( NaN ) ) ; // verdadero console.log ( Number.isNaN ( " no convertido" )); // falso console.log ( Number.isNaN ( NaN )) ; // verdadero
Los BigInts se pueden utilizar para números enteros arbitrariamente grandes . Especialmente números enteros mayores que 2 53 - 1, que es el número más grande que JavaScript puede representar de manera confiable con el primitivo Number y representado por la constante Number.MAX_SAFE_INTEGER.
Al dividir BigInts, los resultados se truncan .
Una cadena en JavaScript es una secuencia de caracteres. En JavaScript, las cadenas se pueden crear directamente (como literales) colocando la serie de caracteres entre comillas dobles (") o simples ('). Dichas cadenas deben escribirse en una sola línea, pero pueden incluir caracteres de nueva línea escapados (como \n). El estándar de JavaScript permite el carácter de comilla invertida (`, también conocido como acento grave o tilde invertido) para citar cadenas literales de varias líneas, así como literales de plantilla, que permiten la interpolación de expresiones evaluadas con conversión de tipo dentro de una cadena. [9]
const greeting = "¡Hola, mundo!" ; const anotherGreeting = 'Saludos, gente de la Tierra.' ; const aMultilineGreeting = `Saludos cordiales, John Doe.` // Los literales de plantilla convierten el tipo de expresiones evaluadas en interpolaciones y las hacen iguales en la cadena. const templateLiteral = `Esto es lo que se almacena en anotherGreeting: ${ anotherGreeting } .` ; console . log ( templateLiteral ); // 'Esto es lo que se almacena en anotherGreeting: 'Saludos, gente de la Tierra.'
Se puede acceder a caracteres individuales dentro de una cadena mediante el método charAt (proporcionado por String.prototype ). Esta es la forma preferida para acceder a caracteres individuales dentro de una cadena, ya que también funciona en navegadores no modernos:
const h = saludo . charAt ( 0 );
En los navegadores modernos, se puede acceder a caracteres individuales dentro de una cadena (como cadenas con un solo carácter) a través de la misma notación que las matrices:
const h = saludo [ 0 ];
Sin embargo, las cadenas de JavaScript son inmutables :
saludo [ 0 ] = "H" ; // Falla.
La aplicación del operador de igualdad ("==") a dos cadenas devuelve verdadero si las cadenas tienen el mismo contenido, es decir, tienen la misma longitud y contienen la misma secuencia de caracteres (las mayúsculas y minúsculas son importantes para los alfabetos). Por lo tanto:
const x = "Mundo" ; const compare1 = ( "Hola, " + x == "Hola, Mundo" ); // Aquí compare1 contiene verdadero. const compare2 = ( "Hola, " + x == "Hola, Mundo" ); // Aquí compare2 contiene ... // ... falso ya que los ... // ... primeros caracteres ... // ... de ambos operandos ... // ... no son del mismo caso.
Las comillas del mismo tipo no se pueden anidar a menos que se escapen .
sea x = '"¡Hola, mundo!" dijo.' ; // Está bien. x = "" ¡Hola , mundo ! " dijo." ; // No está bien. x = "\"¡Hola, mundo!" dijo." ; // Funciona escapando " con \"
El constructor de cadena crea un objeto de cadena (un objeto que envuelve una cadena):
const saludo = new String ( "¡Hola, mundo!" );
Estos objetos tienen un método valueOf que devuelve la cadena primitiva contenida en ellos:
const s = new String ( "Hola!" ); typeof s ; // Es 'objeto'. typeof s . valueOf (); // Es 'cadena'.
La igualdad entre dos objetos String no se comporta como con los primitivos de cadena:
const s1 = new String ( "Hola!" ); const s2 = new String ( "Hola!" ); s1 == s2 ; // Es falso, porque son dos objetos distintos. s1 . valueOf () == s2 . valueOf (); // Es verdadero.
JavaScript proporciona un tipo de datos booleano con literales verdaderos y falsos . El operador typeof devuelve la cadena "boolean" para estos tipos primitivos . Cuando se utiliza en un contexto lógico, 0 , -0 , null , NaN , undefined y la cadena vacía ( "" ) se evalúan como falsos debido a la conversión automática de tipos . Todos los demás valores (el complemento de la lista anterior) se evalúan como verdaderos , incluidas las cadenas "0" , "false" y cualquier objeto.
La coerción de tipos automática por parte de los operadores de comparación de igualdad ( ==
y !=
) se puede evitar utilizando los operadores de comparación con verificación de tipos ( ===
y !==
).
Cuando se requiere conversión de tipo, JavaScript convierte operandos Boolean , Number , String u Object de la siguiente manera: [10]
Douglas Crockford defiende los términos "truthy" y "falsy" para describir cómo se comportan los valores de varios tipos cuando se evalúan en un contexto lógico, especialmente en relación con los casos extremos. [11]
Los operadores lógicos binarios devolvían un valor booleano en las primeras versiones de JavaScript, pero ahora devuelven uno de los operandos en su lugar. Se devuelve el operando izquierdo, si se puede evaluar como : false , en el caso de la conjunción : ( ), o true , en el caso de la disyunción : ( ); de lo contrario, se devuelve el operando derecho. La coerción de tipo automática por parte de los operadores de comparación puede diferir para los casos de operandos mixtos booleanos y compatibles con números (incluidas las cadenas que se pueden evaluar como un número u objetos que se pueden evaluar como una cadena de este tipo), porque el operando booleano se comparará como un valor numérico. Esto puede ser inesperado. Una expresión se puede convertir explícitamente a un primitivo booleano duplicando el operador de negación lógica : ( !! ), utilizando la función Boolean() o utilizando el operador condicional : ( ).a && b
a || b
c ? t : f
// Coerción de tipo automática console.log ( true == 2 ) ; // falso... verdadero → 1 !== 2 ← 2 console.log ( false == 2 ); // falso... falso → 0 !== 2 ← 2 console.log(true == 1); // verdadero.... verdadero → 1 === 1 ← 1 console.log( false == 0 ) ; // verdadero .... falso → 0 === 0 ← 0 console.log ( true == " 2 " ) ; // falso ... verdadero → 1 !== 2 ← "2" console.log ( false == "2" ); // falso ... falso → 0 ! == 2 ← "2" console.log ( true == " 1" ); // verdadero.... verdadero → 1 === 1 ← "1" consola . iniciar sesión ( falso == "0" ); // verdadero.... falso → 0 === 0 ← "0" consola . iniciar sesión ( falso == "" ); // verdadero.... falso → 0 === 0 ← "" consola . iniciar sesión ( falso == NaN ); // falso... falso → 0 !== NaN console . log ( NaN == NaN ); // falso...... NaN no es equivalente a nada, incluido NaN. // Comparación de tipo comprobado (sin conversión de tipos y valores) console.log ( true === 1 ); // false ... los tipos de datos no coinciden // Coerción de tipo explícita console.log ( true === !! 2 ) ; // verdadero... los tipos de datos y valores coinciden console.log ( true === !! 0 ) ; // falso ... los tipos de datos coinciden, pero los valores difieren console.log ( 1 ? true : false ); // verdadero... solo ±0 y NaN son números "falsos" console.log ( "0" ? true : false ); // verdadero ... solo la cadena vacía es "falsa" console.log ( Boolean ( {})); // verdadero... todos los objetos son " veraces "
El operador new se puede utilizar para crear un contenedor de objeto para un primitivo booleano. Sin embargo, el operador typeof no devuelve boolean para el contenedor de objeto, sino que devuelve object . Debido a que todos los objetos se evalúan como true , se debe utilizar un método como .valueOf() o .toString() para recuperar el valor encapsulado. Para la conversión explícita al tipo booleano, Mozilla recomienda que se utilice la función Boolean() (sin new ) en lugar del objeto booleano.
const b = new Boolean ( false ); // Objeto false {} const t = Boolean ( b ); // Booleano true const f = Boolean ( b . valueOf ()); // Booleano false let n = new Boolean ( b ); // No recomendado n = new Boolean ( b . valueOf ()); // Preferido si ( 0 || - 0 || "" || null || indefinido || b . valueOf () || ! new Boolean () || ! t ) { console . log ( "Nunca esto" ); } de lo contrario si ([] && {} && b && typeof b === "object" && b . toString () === "false" ) { console . log ( "Siempre esto" ); }
Novedad en ECMAScript6: un símbolo es un identificador único e inmutable.
Ejemplo:
sea x = Símbolo ( 1 ); const y = Símbolo ( 1 ); x === y ; // => falso const objetoSímbolo = {}; const objetoNormal = {}; // dado que x e y son únicos, // pueden usarse como claves únicas en un objeto symbolObject [ x ] = 1 ; symbolObject [ y ] = 2 ; objeto-símbolo [ x ]; // => 1 objeto-símbolo [ y ]; // => 2 // en comparación con las teclas numéricas normales normalObject [ 1 ] = 1 ; normalObject [ 1 ] = 2 ; // anula el valor de 1 objetoNormal [ 1 ]; // => 2 // cambiar el valor de x no cambia la clave almacenada en el objeto x = Symbol ( 3 ); symbolObject [ x ]; // => undefined // cambiar x de nuevo solo crea otro Símbolo único x = Símbolo ( 1 ); symbolObject [ x ]; // => indefinido
También hay símbolos bien conocidos .
Una de ellas es Symbol.iterator
que si algo implementa Symbol.iterator
, es iterable:
const x = [ 1 , 2 , 3 , 4 ]; // x es una matriz x [ Símbolo . iterador ] === Matriz . prototipo [ Símbolo . iterador ]; // y las matrices son iterables const xIterator = x [ Symbol . iterator ](); // La función [Symbol.iterator] debe proporcionar un iterador para x xIterator . next (); // { valor: 1, hecho: falso } xIterator . next (); // { valor: 2, hecho: falso } xIterator . next (); // { valor: 3, hecho: falso } xIterator . next (); // { valor: 4, hecho: falso } xIterator . next (); // { valor: indefinido, hecho: verdadero } xIterator . next (); // { valor: indefinido, hecho: verdadero } // Los bucles for..of iteran automáticamente los valores for ( const value of x ) { console . log ( value ); // 1 2 3 4 } // Los conjuntos también son iterables: [ Símbolo . iterador ] en Conjunto . prototipo ; // verdadero para ( const valor de nuevo Set ([ 'manzana' , 'naranja' ])) { console . log ( valor ); // "manzana" "naranja" }
El lenguaje JavaScript ofrece un conjunto de objetos nativos . Los objetos nativos de JavaScript se consideran parte de la especificación de JavaScript. Independientemente del entorno de JavaScript, este conjunto de objetos siempre debería estar disponible.
Un array es un objeto de JavaScript cuyo prototipo se obtiene a partir del Array
constructor, diseñado específicamente para almacenar valores de datos indexados por claves enteras. Los arrays, a diferencia del tipo Object básico, se construyen con métodos y propiedades para ayudar al programador en tareas rutinarias (por ejemplo, join
, slice
y push
).
Al igual que en la familia C , las matrices utilizan un esquema de indexación basado en cero: un valor que se inserta en una matriz vacía mediante el push
método ocupa el índice 0 de la matriz.
const myArray = []; // Apunta la variable myArray a un array vacío recién creado myArray . push ( "hello World" ); // Rellena el siguiente índice vacío, en este caso 0 console . log ( myArray [ 0 ]); // Equivalente a console.log("hello World");
Las matrices tienen una length
propiedad que garantiza que siempre será mayor que el índice entero más grande utilizado en la matriz. Se actualiza automáticamente si se crea una propiedad con un índice aún mayor. Si se escribe un número menor en la length
propiedad, se eliminarán los índices mayores.
Se puede acceder a los elementos de Array
s utilizando la notación de acceso a propiedades de objetos normal:
myArray [ 1 ]; // el segundo elemento en myArray myArray [ "1" ];
Los dos ejemplos anteriores son equivalentes. No es posible utilizar la notación de "punto" ni cadenas con representaciones alternativas del número:
myArray .1 ; // error de sintaxis myArray [ "01" ]; // no es lo mismo que myArray[1]
La declaración de una matriz puede utilizar un Array
literal o el Array
constructor:
deje miArray ; // Literales de matriz myArray = [ 1 , 2 ]; // longitud de 2 myArray = [ 1 , 2 ,]; // misma matriz - También puede tener una coma adicional al final // También es posible no rellenar partes de la matriz myArray = [ 0 , 1 , /* agujero */ , /* agujero */ , 4 , 5 ]; // longitud de 6 myArray = [ 0 , 1 , /* agujero */ , /* agujero */ , 4 , 5 ,]; // misma matriz myArray = [ 0 , 1 , /* agujero */ , /* agujero */ , 4 , 5 , /* agujero */ ,]; // longitud de 7 // Con el constructor myArray = new Array ( 0 , 1 , 2 , 3 , 4 , 5 ); // longitud de 6 myArray = new Array ( 365 ); // una matriz vacía con longitud 365
Las matrices se implementan de modo que solo los elementos definidos utilicen memoria; son " matrices dispersas ". La configuración y solo utiliza espacio para estos dos elementos, al igual que cualquier otro objeto. El de la matriz se seguirá informando como 58. La longitud máxima de una matriz es 4.294.967.295, que corresponde a un número binario de 32 bits (1111111111111111111111111111111111) 2 .myArray[10] = 'someThing'
myArray[57] = 'somethingOther'
length
Se puede utilizar el literal de declaración de objeto para crear objetos que se comporten de manera muy similar a las matrices asociativas en otros lenguajes:
const dog = { color : "brown" , size : "large" }; dog [ "color" ]; // da como resultado "brown" dog . color ; // también da como resultado "brown"
Se pueden utilizar los literales de declaración de objetos y matrices para crear rápidamente matrices que sean asociativas, multidimensionales o ambas. (Técnicamente, JavaScript no admite matrices multidimensionales, pero se pueden imitar con matrices de matrices).
const gatos = [{ color : "marrón" , tamaño : "grande" }, { color : "negro" , tamaño : "pequeño" }]; gatos [ 0 ][ "tamaño" ]; // da como resultado "grande" const dogs = { rover : { color : "brown" , size : "large" }, spot : { color : "black" , size : "small" }}; dogs [ "spot" ][ "size" ]; // da como resultado "small" dogs . rover . color ; // da como resultado "brown"
Un Date
objeto almacena un recuento de milisegundos con signo, donde cero representa el 1970-01-01 00:00:00 UT y un rango de ±10 8 días. Hay varias formas de proporcionar argumentos al Date
constructor. Tenga en cuenta que los meses se basan en cero.
new Date (); // crea una nueva instancia de Date que represente la fecha/hora actual. new Date ( 2010 , 2 , 1 ); // crea una nueva instancia de Date que represente 2010-Mar-01 00:00:00 new Date ( 2010 , 2 , 1 , 14 , 25 , 30 ); // crea una nueva instancia de Date que represente 2010-Mar-01 14:25:30 new Date ( "2010-3-1 14:25:30" ); // crea una nueva instancia de Date a partir de una String.
Se proporcionan métodos para extraer campos, así como un útil toString
:
const d = nueva Fecha ( 2010 , 2 , 1 , 14 , 25 , 30 ); // 2010-Mar-01 14:25:30; // Muestra '2010-3-1 14:25:30': console.log ( d.getFullYear ( ) + ' - ' + ( d.getMonth ( ) + 1 ) + ' -' + d.getDate ( ) + ' ' + d.getHours () + ' :' + d.getMinutes ( ) + ' :' + d.getSeconds ( ) ) ; // El toString incorporado devuelve algo como 'Lun 01 Mar 2010 14:25:30 GMT-0500 (EST)': console . log ( d );
Se pueden crear mensajes de error personalizados utilizando la Error
clase:
lanzar nuevo Error ( "Algo salió mal." );
Estos pueden detectarse mediante bloques try...catch...finally como se describe en la sección sobre manejo de excepciones.
El objeto Math contiene varias constantes relacionadas con las matemáticas (por ejemplo, π ) y funciones (por ejemplo, coseno). (Tenga en cuenta que el objeto Math no tiene constructor, a diferencia de Array o Date . Todos sus métodos son "estáticos", es decir, métodos de "clase"). Todas las funciones trigonométricas utilizan ángulos expresados en radianes , no en grados o grados centesimales .
/expresión/ . test ( cadena ); // devuelve el valor booleano "cadena" . search ( /expresión/ ); // devuelve la posición Número "cadena" . replace ( /expresión/ , reemplazo ); // Aquí hay algunos ejemplos if ( /Tom/ . test ( "Mi nombre es Tom" )) console . log ( "¡Hola Tom!" ); console . log ( "Mi nombre es Tom" . search ( /Tom/ )); // == 11 (letras antes de Tom) console . log ( "Mi nombre es Tom" . replace ( /Tom/ , "John" )); // == "Mi nombre es John"
// \d - dígito // \D - no dígito // \s - espacio // \S - no espacio // \w - carácter de palabra // \W - no palabra // [ ] - uno de // [^] - uno que no sea de // - - rangoif ( /\d/ . test ( '0' )) console . log ( 'Dígito' ); if ( /[0-9]/ . test ( '6' )) console . log ( 'Dígito' ); if ( /[13579]/ . test ( '1' )) console . log ( 'Número impar' ); if ( /\S\S\s\S\S\S\S/ . test ( 'Mi nombre' )) console . log ( 'Formato correcto' ); if ( /\w\w\w/ . test ( 'Tom' )) console . log ( 'Hola Tom' ); if ( /[a-zA-Z]/ . test ( 'B' )) console . log ( 'Letra' );
// A...Z a...z 0...9 - alfanumérico // \u0000...\uFFFF - hexadecimal Unicode // \x00...\xFF - hexadecimal ASCII // \t - tabulación // \n - nueva línea // \r - CR // . - cualquier carácter // | - Osi ( /Tm/ . test ( 'Tom' )) console . log ( 'Hola Tom, Tam o Tim' ); si ( /A|B/ . test ( "A" )) console . log ( 'A o B' );
// ? - 0 o 1 coincidencia // * - 0 o más // + - 1 o más // {n} - exactamente n // {n,} - n o más // {0,n} - n o menos // {n,m} - rango de n a mif ( /ab?c / .test ( "ac" )) console.log ( " OK" ); // coincidencia: "ac", "abc" if ( /ab*c / .test("ac" )) console.log ( " OK " ) ; // coincidencia : " ac " , "abc", "abbc", "abbbc" etc. if ( /ab+c/ .test ( " abc" )) console.log ( "OK" ); // coincidencia: "abc", "abbc", "abbbc" etc. if ( /ab{3}c / .test ( " abbbc " ) ) console.log ( "OK" ); // coincidencia: "abbbc" if ( /ab{3,}c/ .test ( " abbbc " ) ) console.log ( " OK " ) ; // coincidencia: "abbbc", "abbbbc", "abbbbbc", etc. if ( /ab{1,3}c/ . test ( "abc" )) consola . iniciar sesión ( "Aceptar" ); // coincidencia: "abc", "abbc", "abbbc"
// ^ - la cadena comienza con // $ - la cadena termina conif ( /^My/ . test ( "Mi nombre es Tom" )) console . log ( "¡Hola!" ); if ( /Tom$/ . test ( "Mi nombre es Tom" )) console . log ( "¡Hola Tom!" );
// ( ) - agrupa caracteresif ( /water(marca)?/ . test ( "marca de agua" )) console . log ( "¡Aquí hay agua!" ); // coincidencia: "agua", "marca de agua", if ( /(Tom)|(John)/ . test ( "John" )) console . log ( "¡Hola Tom o John!" );
// /g - global // /i - ignora mayúsculas y minúsculas // /m - permite que las coincidencias abarquen varias líneasconsole.log ( "hola tom!" .replace(/Tom/i, "Juan")); // == "¡hola Juan!" console.log( " ratatam " .replace ( / ta / , " tu " ) ) ; // == " ratutam " console.log ( " ratatam " .replace ( / ta/g , "tu" )); // == " ratutum"
my_array = my_string . split ( my_delimiter ); // ejemplo my_array = "perro,gato,vaca" . split ( "," ); // my_array==["perro", "gato", "vaca"]; my_array = my_string .match ( my_expression ); // ejemplo my_array = "Empezamos a las 11:30, 12:15 y 16:45" .match ( / \d\d:\d\d/g ) ; // my_array==["11:30","12:15","16:45"];
const myRe = /(\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2})/ ; const results = myRe . exec ( "La fecha y hora son 2009-09-08 09:37:08." ); if ( results ) { console . log ( "Coincidencia: " + results [ 0 ]); // Coincidencia completa const my_date = results [ 1 ]; // Primer grupo == "2009-09-08" const my_time = results [ 2 ]; // Segundo grupo == "09:37:08" console . log ( `Es ${ my_time } en ${ my_date } ` ); } else console . log ( "¡No se encontró una fecha válida!" );
Cada función en JavaScript es una instancia del Function
constructor:
// x, y es el argumento. 'return x + y' es el cuerpo de la función, que es el último en la lista de argumentos. const add = new Function ( 'x' , 'y' , 'return x + y' ); add ( 1 , 2 ); // => 3
La función de suma anterior también se puede definir utilizando una expresión de función:
const add = function ( x , y ) { return x + y ; }; add ( 1 , 2 ); // => 3
En ES6, se agregó la sintaxis de función de flecha, lo que permite que las funciones que devuelven un valor sean más concisas. También conservan el this
del objeto global en lugar de heredar el del lugar donde se llamó o en qué se llamó, a diferencia de la function() {}
expresión.
const add = ( x , y ) => { return x + y ;}; // los valores también se pueden devolver implícitamente (es decir, no se necesita una declaración de retorno) const addImplicit = ( x , y ) => x + y ; añadir ( 1 , 2 ); // => 3 addImplicit ( 1 , 2 ) // => 3
Para las funciones que necesitan ser elevadas, existe una expresión separada:
función suma ( x , y ) { devuelve x + y ; } suma ( 1 , 2 ); // => 3
La elevación le permite utilizar la función antes de que se "declare":
add ( 1 , 2 ); // => 3, no es una función ReferenceError add ( x , y ) { return x + y ; }
Una instancia de función tiene propiedades y métodos.
función restar ( x , y ) { devolver x - y ; } console.log ( subtract.length ) ; // = > 2 , aridad de la función (número de argumentos ) console.log ( subtract.toString ( ) ) ; /* "función restar(x, y) { devolver x - y; }" */
El operador '+' está sobrecargado : se utiliza para la concatenación de cadenas y la suma aritmética. Esto puede causar problemas si se mezclan cadenas y números por accidente. Como operador unario, puede convertir una cadena numérica en un número.
// Concatenar 2 cadenas console.log('He' + ' llo ' ) ; // muestra Hola // Suma dos números console.log ( 2 + 6 ); // muestra 8 // Agregar un número y una cadena da como resultado una concatenación (de izquierda a derecha) console.log ( 2 + ' 2' ); // muestra 22 console.log ( '$' + 3 + 4 ); // muestra $ 34, pero se esperaba $7 console.log ( ' $ ' + ( 3 + 4 )); // muestra $ 7 console.log ( 3 + 4 + '7' ); // muestra 77, los números siguen siendo números hasta que se agrega una cadena // Convierte una cadena en un número usando el suma unario console.log ( + '2' === 2 ) ; // muestra verdadero console.log ( + 'Hello' ); // muestra NaN
De manera similar, el operador '*' está sobrecargado: puede convertir una cadena en un número.
console.log ( 2 + '6' * 1 ) ; // muestra 8 console.log ( 3 * ' 7' ) ; // 21 console.log ( ' 3' * '7' ); // 21 console.log ( ' hola' * 'mundo' ); // muestra NaN
JavaScript admite los siguientes operadores aritméticos binarios :
JavaScript admite los siguientes operadores aritméticos unarios :
sea x = 1 ; console . log ( ++ x ); // x se convierte en 2; muestra 2 console . log ( x ++ ); // muestra 2; x se convierte en 3 console . log ( x ); // x es 3; muestra 3 console . log ( x -- ); // muestra 3; x se convierte en 2 console . log ( x ); // muestra 2; x es 2 console . log ( -- x ); // x se convierte en 1; muestra 1
El operador módulo muestra el resto después de la división por el módulo. Si se trata de números negativos, el valor devuelto depende del operando.
const x = 17 ; console . log ( x % 5 ); // muestra 2 console . log ( x % 6 ); // muestra 5 console . log ( - x % 5 ); // muestra -2 console . log ( - x %- 5 ); // muestra -2 console . log ( x %- 5 ); // muestra 2
Para devolver siempre un número no negativo, vuelva a sumar el módulo y aplique el operador de módulo nuevamente:
const x = 17 ; console . log (( - x % 5 + 5 ) % 5 ); // muestra 3
También podrías hacer:
const x = 17 ; console . log ( Math . abs ( - x % 5 )); // también 3
Asignación de tipos primitivos
sea x = 9 ; x += 1 ; console . log ( x ); // muestra: 10 x *= 30 ; console . log ( x ); // muestra: 300 x /= 6 ; console . log ( x ); // muestra: 50 x -= 3 ; console . log ( x ); // muestra: 47 x %= 7 ; console . log ( x ); // muestra: 5
Asignación de tipos de objetos
/** * Para aprender objetos JavaScript... */ const object_1 = { a : 1 }; // asigna la referencia del objeto recién creado a object_1 let object_2 = { a : 0 }; let object_3 = object_2 ; // object_3 hace referencia al mismo objeto que object_2 hace con object_3 . a = 2 ; message (); // muestra 1 2 2 object_2 = object_1 ; // object_2 ahora hace referencia al mismo objeto que object_1 // object_3 todavía hace referencia a lo que object_2 hacía referencia antes message (); // muestra 1 1 2 object_2 . a = 7 ; // modifica object_1 message (); // muestra 7 7 2 object_3 . a = 5 ; // object_3 no cambia object_2 message (); // muestra 7 7 5 objeto_3 = objeto_2 ; objeto_3 . a = 4 ; // objeto_3 cambia objeto_1 y objeto_2 mensaje (); // muestra 4 4 4 /** * Imprime el mensaje console.log */ function message () { console . log ( object_1 . a + " " + object_2 . a + " " + object_3 . a ); }
En JavaScript de Mozilla, desde la versión 1.7, la asignación de desestructuración permite asignar partes de estructuras de datos a varias variables a la vez. El lado izquierdo de una asignación es un patrón que se asemeja a un literal de objeto/matriz anidado arbitrariamente que contiene l-lvalues en sus hojas que deben recibir las subestructuras del valor asignado.
sea a , b , c , d , e ; [ a , b , c ] = [ 3 , 4 , 5 ]; console.log ( ` $ { a } , ${ b } , ${ c } ` ); // muestra : 3,4,5 e = { foo : 5 , bar : 6 , baz : [ 'Baz' , 'Contenido' ]}; const arr = []; ({ baz : [ arr [ 0 ], arr [ 3 ]], foo : a , bar : b } = e ); console.log ( ` $ { a } , ${ b } , ${ arr } ` ); // muestra : 5,6,Baz,,,Contenido [ a , b ] = [ b , a ]; // intercambia el contenido de a y b console . log ( a + ',' + b ); // muestra: 6,5 [ a , b , c ] = [ 3 , 4 , 5 ]; // permutaciones [ a , b , c ] = [ b , c , a ]; console . log ( ` ${ a } , ${ b } , ${ c } ` ); // muestra: 4,5,3
El estándar ECMAScript 2015 introdujo el ...
operador de matriz " ", para los conceptos relacionados de "sintaxis de propagación" [12] y "parámetros de descanso". [13] La propagación de objetos se agregó en ECMAScript 2018.
La sintaxis de propagación proporciona otra forma de desestructurar matrices y objetos. En el caso de las matrices, indica que los elementos se deben utilizar como parámetros en una llamada de función o como elementos en un literal de matriz. En el caso de los objetos, se puede utilizar para fusionar objetos o anular propiedades.
En otras palabras, " ...
" transforma " [...foo]
" en " [foo[0], foo[1], foo[2]]
", y " this.bar(...foo);
" en " this.bar(foo[0], foo[1], foo[2]);
", y " { ...bar }
" en { prop: bar.prop, prop2: bar.prop2 }
.
constante a = [ 1 , 2 , 3 , 4 ]; // Se puede utilizar varias veces en la misma expresión.constante b = [... a , ... a ]; // b = [1, 2, 3, 4, 1, 2, 3, 4]; //Se puede combinar con elementos no propagados.constante c = [ 5 , 6 , ... a , 7 , 9 ]; // c = [5, 6, 1, 2, 3, 4, 7, 9]; // A modo de comparación, hacer esto sin el operador de propagación// crea una matriz anidada.constante d = [ a , a ]; // d = [[1, 2, 3, 4], [1, 2, 3, 4]] // Funciona igual con llamadas de función.función foo ( arg1 , arg2 , arg3 ) { consola .log ( ` ${ arg1 } : ${ arg2 } : ${ arg3 } ` ) ;}// Puedes usarlo incluso si pasa más parámetros de los que utilizará la funciónfoo (... un ); // "1:2:3" → foo(a[0], a[1], a[2], a[3]); // Puedes mezclarlo con parámetros no propagadosfoo ( 5 , ... a , 6 ); // "5:1:2" → foo(5, a[0], a[1], a[2], a[3], 6); // A modo de comparación, hacer esto sin el operador de propagación// asigna la matriz a arg1 y nada a los demás parámetros.foo ( a ); // "1,2,3,4:indefinido:indefinido" constante barra = { a : 1 , b : 2 , c : 3 }; // Esto copiaría el objetoconst copia = { ... barra }; // copia = { a: 1, b: 2, c: 3 }; // "b" se anularía aquíconst anulación = { ... bar , b : 4 }; // anulación = { a: 1, c: 3, b: 4 }
Cuando ...
se utiliza en una declaración de función , indica un parámetro restante . El parámetro restante debe ser el último parámetro nombrado en la lista de parámetros de la función. Se le asignará un Array
que contenga todos los argumentos pasados a la función que excedan los otros parámetros nombrados. En otras palabras, obtiene "el resto" de los argumentos pasados a la función (de ahí el nombre).
función foo ( a , b , ... c ) { console.log ( c.length ) ; } foo ( 1 , 2 , 3 , 4 , 5 ); // "3" → c = [3, 4, 5] foo ( 'a' , 'b' ); // "0" → c = []
Los parámetros de descanso son similares al objeto de Javascript arguments
, que es un objeto similar a una matriz que contiene todos los parámetros (con nombre y sin nombre) en la llamada de función actual. arguments
Sin embargo, a diferencia de , los parámetros de descanso son objetos verdaderos , por lo que se pueden usar Array
métodos como .slice()
y directamente en ellos..sort()
Las variables que hacen referencia a objetos son iguales o idénticas solo si hacen referencia al mismo objeto:
const obj1 = { a : 1 }; const obj2 = { a : 1 }; const obj3 = obj1 ; console . log ( obj1 == obj2 ); //falso console . log ( obj3 == obj1 ); //verdadero console . log ( obj3 === obj1 ); //verdadero
Véase también Cadena.
JavaScript proporciona cuatro operadores lógicos:
NOT = !a
)OR = a || b
) y conjunción ( AND = a && b
)c ? t : f
)En el contexto de una operación lógica, cualquier expresión se evalúa como verdadera excepto las siguientes :
""
, ''
,0
, -0
, NaN
,null
, undefined
,false
.La función booleana se puede utilizar para convertir explícitamente a un primitivo de tipo Boolean
:
// Sólo las cadenas vacías devuelven falso console.log ( Boolean ( " " ) === false ); console.log ( Boolean ( " false" ) === true ) ; console.log ( Boolean ( " 0" ) === true ) ; // Solo cero y NaN devuelven falso console.log ( Boolean ( NaN ) === false ); console.log ( Boolean ( 0 ) === false ) ; console.log ( Boolean ( -0 ) === false ) ; // equivalente a -1 * 0 console.log ( Boolean ( -2 ) === true ) ; // Todos los objetos devuelven verdadero console.log ( Boolean ( this ) === true ) ; console.log(Boolean ( { } ) === true ) ; console.log ( Boolean ( [ ]) === true ); // Estos tipos devuelven falso console.log ( Boolean ( null ) === false ) ; console.log ( Boolean ( undefined ) === false ) ; // equivalente a Boolean( )
El operador NOT evalúa su operando como un booleano y devuelve la negación. Si se utiliza el operador dos veces seguidas, como doble negación , se convierte explícitamente una expresión en un primitivo de tipo booleano:
consola . log ( ! 0 === Booleano ( ! 0 )); consola . log ( Booleano ( ! 0 ) === !! 1 ); consola . log ( !! 1 === Booleano ( 1 )); consola . log ( !! 0 === Booleano ( 0 )); consola . log ( Booleano ( 0 ) === ! 1 ); consola . log ( ! 1 === Booleano ( ! 1 )); consola . log ( ! "" === Booleano ( ! "" )); consola . log ( Booleano ( ! "" ) === !! "s" ); consola . log ( !! "s" === Booleano ( "s" )); consola . log ( !! "" === Booleano ( "" )); consola . log ( Booleano ( "" ) === ! "s" ); consola . log ( ! "s" === Booleano ( ! "s" ));
El operador ternario también se puede utilizar para conversión explícita:
console.log ( [] == false ); console.log ( [] ? true : false ); // “veraz”, pero la comparación usa [].toString() console.log ( [ 0 ] == false ); console.log ([ 0 ] ? true : false ); // [0].toString() == "0" console.log ("0" == false); console.log ( " 0 " ? true : false ) ; // " 0 " → 0 ... ( 0 == 0 ) ... 0 ← false console.log ( [ 1 ] == true ); console.log ([ 1 ] ? true : false ); // [1 ] .toString ( ) == " 1" console.log ( "1" == true ) ; console.log ( "1" ? true : false ); // " 1 " → 1 ... (1 == 1) ... 1 ← verdadero console.log ([ 2 ] != verdadero ); console.log ([ 2 ] ? verdadero : falso ); // [2].toString() == "2" console.log ( " 2" ? = verdadero ); console.log ( "2" ? verdadero : falso ); // "2" → 2 ... (2?= 1) ... 1 ← verdadero
Las expresiones que utilizan funciones como post–incrementación ( ) tienen un efecto secundarioi++
anticipado . JavaScript proporciona una evaluación de cortocircuito de las expresiones; el operando derecho solo se ejecuta si el operando izquierdo no es suficiente para determinar el valor de la expresión.
console.log ( a || b ); // Cuando a es verdadero, no hay razón para evaluar b. console.log ( a && b ); // Cuando a es falso, no hay razón para evaluar b. console.log(c?t: f ) ; // Cuando c es verdadero , no hay razón para evaluar f.
En las primeras versiones de JavaScript y JScript , los operadores lógicos binarios devolvían un valor booleano (como la mayoría de los lenguajes de programación derivados de C). Sin embargo, todas las implementaciones contemporáneas devuelven uno de sus operandos en su lugar:
console.log ( a || b ); // si a es verdadero, devuelve a, de lo contrario devuelve b console.log ( a && b ) ; // si a es falso, devuelve a, de lo contrario devuelve b
Los programadores que están más familiarizados con el comportamiento en C pueden encontrar esta característica sorprendente, pero permite una expresión más concisa de patrones como null coalescing :
const s = t || "(predeterminado)" ; // asigna t, o el valor predeterminado, si t es nulo, vacío, etc.
JavaScript admite los siguientes operadores binarios bit a bit :
Ejemplos:
const x = 11 & 6 ; consola . log ( x ); // 2
JavaScript admite el siguiente operador bit a bit unario :
JavaScript admite los siguientes operadores de asignación binaria:
Ejemplos:
sea x = 7 ; consola . log ( x ); // 7 x <<= 3 ; consola . log ( x ); // 7->14->28->56
Ejemplos:
let str = "ab" + "cd" ; // cadena "abcd" += "e" ; // "abcd" const str2 = "2" + 2 ; // "22", no "4" o 4.
El operador más cercano de JavaScript??
es , el "operador de coalescencia nula", que se agregó al estándar en la 11.ª edición de ECMAScript . [14] En versiones anteriores, se podía usar a través de un complemento de Babel y en TypeScript . Evalúa su operando de la izquierda y, si el valor del resultado no es "nulo" ( null
o undefined
), toma ese valor como su resultado; de lo contrario, evalúa el operando de la derecha y toma el valor resultante como su resultado.
En el siguiente ejemplo, a
se asignará el valor de b
si el valor de b
no es null
o undefined
, en caso contrario se asignará 3.
constante a = b ?? 3 ;
Antes del operador de fusión nulo, los programadores usaban el operador lógico OR ( ||
). Pero donde ??
busca específicamente null
or undefined
, el ||
operador busca cualquier valor falso: null
, undefined
, ""
, 0
, NaN
, y por supuesto, false
.
En el siguiente ejemplo, a
se asignará el valor de b
si el valor de b
es verdadero, de lo contrario se asignará 3.
constante a = b || 3 ;
Un par de llaves { }
y una secuencia de declaraciones encerradas constituyen una declaración compuesta, que se puede utilizar en cualquier lugar donde se pueda utilizar una declaración.
if ( expr ) { //declaraciones; } else if ( expr2 ) { //declaraciones; } else { //declaraciones; }
El operador condicional crea una expresión que se evalúa como una de dos expresiones según una condición. Esto es similar a la declaración if que selecciona una de dos declaraciones para ejecutar según una condición. Es decir, el operador condicional es para las expresiones lo que if es para las declaraciones.
const resultado = condición ? expresión : alternativa ;
es lo mismo que:
if ( condición ) { const resultado = expresión ; } else { const resultado = alternativa ; }
A diferencia de la declaración if , el operador condicional no puede omitir su "rama else".
La sintaxis de la declaración switch de JavaScript es la siguiente:
switch ( expr ) { case SOMEVALUE : // declaraciones; break ; case ANOTHERVALUE : // declaraciones para cuando ANOTHERVALUE || ORNAOTHERONE // ninguna declaración break, pasando al siguiente caso case ORANOTHERONE : // declaraciones específicas de ORANOTHERONE (es decir, !ANOTHERVALUE && ORANOTHER); break ; //La responsabilidad termina aquí. case YETANOTHER : // declaraciones; break ; default : // declaraciones; break ; }
break;
es opcional; sin embargo, suele ser necesario, ya que de lo contrario la ejecución del código continuará hasta el cuerpo del siguiente bloque de caso. Este comportamiento de transición se puede utilizar cuando el mismo conjunto de instrucciones se aplica en varios casos, creando efectivamente una disyunción entre esos casos.La sintaxis del bucle for de JavaScript es la siguiente:
for ( inicial ; condición ; declaración del bucle ) { /* las declaraciones se ejecutarán cada vez que se realice un ciclo del bucle for{}, mientras se cumpla la condición */ }
o
para ( inicial ; condición ; declaración de bucle ( iteración )) // una declaración
La sintaxis de JavaScript for ... in loop
es la siguiente:
para ( var nombre_propiedad en algún_objeto ) { // declaraciones que utilizan algún_objeto[nombre_propiedad]; }
if (some_object.hasOwnProperty(property_name)) { ...
Array.prototype.newMethod = function() {...
for ... in
La sintaxis del bucle while de JavaScript es la siguiente:
mientras ( condición ) { declaración1 ; declaración2 ; declaración3 ; ... }
La sintaxis de JavaScript do ... while loop
es la siguiente:
hacer { declaración1 ; declaración2 ; declaración3 ; ... } mientras ( condición );
La declaración with agrega todas las propiedades y métodos del objeto dado al alcance del siguiente bloque, permitiendo que se haga referencia a ellos como si fueran variables locales.
con ( documento ) { const a = getElementById ( 'a' ); const b = getElementById ( 'b' ); const c = getElementById ( 'c' ); };
La semántica es similar a la declaración with de Pascal .
Debido a que la disponibilidad de declaraciones with dificulta el rendimiento del programa y se cree que reduce la claridad del código (ya que cualquier variable dada podría en realidad ser una propiedad de un with adjunto ), esta declaración no está permitida en modo estricto .
JavaScript admite etiquetas anidadas en la mayoría de las implementaciones. Los bucles o bloques se pueden etiquetar para la declaración break y los bucles para continue
. Aunque goto
es una palabra reservada, [15] goto
no está implementada en JavaScript.
loop1 : for ( let a = 0 ; a < 10 ; ++ a ) { if ( a === 4 ) break loop1 ; // Se detiene después del cuarto intento console . log ( 'a = ' + a ); loop2 : for ( let b = 0 ; b < 10 ; ++ b ) { if ( b === 3 ) continue loop2 ; // Se omite el número 3 if ( b === 6 ) continue loop1 ; // Continúa el primer bucle, no se muestra 'finished' console . log ( 'b = ' + b ); } // Fin del loop2 console . log ( 'finished' ); } // Fin del loop1 block1 : { console . log ( 'Hello' ); // Muestra 'Hello' break block1 ; console . log ( 'World' ); // Nunca llegará aquí } goto block1 ; // Error de análisis.
Una función es un bloque con una lista de parámetros (posiblemente vacía) a la que normalmente se le asigna un nombre. Una función puede utilizar variables locales. Si sale de la función sin una declaración de retorno, se devuelve el valor undefined .
función gcd ( numero1 , numero2 ) { if ( isNaN ( numero1 * numero2 )) throw TypeError ( "No se permiten argumentos no numéricos." ); numero1 = Math . round ( numero1 ); numero2 = Math . round ( numero2 ); let diferencia = numero1 - numero2 ; if ( diferencia === 0 ) return numero1 ; return diferencia > 0 ? gcd ( numero2 , diferencia ) : gcd ( numero1 , - diferencia ); } console . log ( gcd ( 60 , 40 )); // 20 //En ausencia de paréntesis después del identificador 'gcd' en el lado derecho de la asignación a continuación, //'gcd' devuelve una referencia a la función misma sin invocarla. let mygcd = gcd ; // mygcd y gcd hacen referencia a la misma función. console . log ( mygcd ( 60 , 40 )); // 20
Las funciones son objetos de primera clase y pueden asignarse a otras variables.
La cantidad de argumentos que se dan al llamar a una función puede no corresponderse necesariamente con la cantidad de argumentos en la definición de la función; un argumento nombrado en la definición que no tenga un argumento coincidente en la llamada tendrá el valor undefined (que puede convertirse implícitamente en false). Dentro de la función, también se puede acceder a los argumentos a través del objeto arguments ; esto proporciona acceso a todos los argumentos que usan índices (por ejemplo, ), incluidos aquellos que están más allá de la cantidad de argumentos nombrados. (Si bien la lista arguments tiene una propiedad, no es una instancia de Array ; no tiene métodos como .slice() , .sort() , etc.)arguments[0], arguments[1], ... arguments[n]
.length
función add7 ( x , y ) { if ( ! y ) { y = 7 ; } console.log ( x + y + arguments.length ) ; } ; add7 ( 3 ) ; // 11 add7 ( 3,4 ) ; // 9
Los valores primitivos (número, booleano, cadena) se pasan por valor. En el caso de los objetos, se pasa la referencia al objeto.
const obj1 = { a : 1 }; const obj2 = { b : 2 }; function foo ( p ) { p = obj2 ; // Ignora el parámetro actual p . b = arguments [ 1 ]; } foo ( obj1 , 3 ); // No afecta a obj1 en absoluto. 3 es un parámetro adicional console . log ( ` ${ obj1 . a } ${ obj2 . b } ` ); // escribe 1 3
Las funciones se pueden declarar dentro de otras funciones y acceder a las variables locales de la función externa. Además, implementan cierres completos al recordar las variables locales de la función externa incluso después de que esta haya salido.
sea t = "Arriba" ; sea bar , baz ; función foo () { sea f = "foo var" ; bar = función () { console . log ( f ) }; baz = función ( x ) { f = x ; }; } foo (); baz ( "baz arg" ); bar (); // "baz arg" (no "foo var") aunque foo() haya salido. console . log ( t ); // Arriba
El operador await en JavaScript solo se puede utilizar desde dentro de una función async o en el nivel superior de un módulo . Si el parámetro es una promesa , la ejecución de la función async se reanudará cuando se resuelva la promesa (a menos que la promesa sea rechazada, en cuyo caso se generará un error que se puede manejar con el manejo de excepciones normal de JavaScript ). Si el parámetro no es una promesa, el parámetro en sí se devolverá inmediatamente. [16]
Muchas bibliotecas proporcionan objetos de promesa que también se pueden usar con await, siempre que coincidan con la especificación de promesas nativas de JavaScript. Sin embargo, las promesas de la biblioteca jQuery no eran compatibles con Promises/A+ hasta jQuery 3.0. [17]
He aquí un ejemplo (modificado de este artículo [18] ):
función asíncrona createNewDoc () { let response = await db.post ( { }); // publicar un nuevo documento return db.get ( response.id ); // buscar por id } función asíncrona principal ( ) { try { let doc = await createNewDoc ( ); console.log ( doc ); } catch ( err ) { console.log ( err ); } } principal ( ) ;
Por conveniencia, los tipos normalmente se subdividen en primitivos y objetos . Los objetos son entidades que tienen una identidad (solo son iguales a sí mismos) y que asignan nombres de propiedades a valores ("ranuras" en la terminología de programación basada en prototipos ). Los objetos pueden considerarse como matrices asociativas o hashes, y a menudo se implementan utilizando estas estructuras de datos. Sin embargo, los objetos tienen características adicionales, como una cadena de prototipos , que las matrices asociativas comunes no tienen.
JavaScript tiene varios tipos de objetos integrados, a saber Array
, Boolean
, Date
, Function
, Math
, Number
, Object
, RegExp
y String
. Otros objetos son "objetos host", definidos no por el lenguaje, sino por el entorno de ejecución. Por ejemplo, en un navegador, los objetos host típicos pertenecen al DOM (ventana, formulario, enlaces, etc.).
Los objetos se pueden crear utilizando un constructor o un literal de objeto. El constructor puede utilizar una función Object incorporada o una función personalizada. Por convención, a las funciones constructoras se les asigna un nombre que comienza con una letra mayúscula:
// Constructor const anObject = new Objeto (); // Objeto literal const objectA = {}; const objectA2 = {}; // A != A2, {}s crea nuevos objetos como copias. const objectB = { index1 : 'valor 1' , index2 : 'valor 2' }; // Constructor personalizado (ver más abajo)
Los literales de objeto y los literales de matriz permiten crear fácilmente estructuras de datos flexibles:
const myStructure = { nombre : { nombre : "Mel" , apellido : "Smith" }, edad : 33 , pasatiempos : [ "ajedrez" , "trotar" ] };
Esta es la base de JSON , que es una notación simple que utiliza una sintaxis similar a JavaScript para el intercambio de datos.
Un método es simplemente una función que se ha asignado a un nombre de propiedad de un objeto. A diferencia de muchos lenguajes orientados a objetos, no existe distinción entre una definición de función y una definición de método en JavaScript relacionado con objetos. En cambio, la distinción se produce durante la llamada a la función; una función puede llamarse como un método.
Cuando se llama como método, la variable local estándar this se establece automáticamente en la instancia del objeto a la izquierda de " . ". (También hay métodos call y apply que pueden establecer this explícitamente; algunos paquetes como jQuery hacen cosas inusuales con this ).
En el ejemplo siguiente, se utiliza Foo como constructor. No hay nada especial en un constructor: es simplemente una función simple que inicializa un objeto. Cuando se utiliza con la palabra clave new , como es la norma, se establece en un objeto en blanco recién creado.
Tenga en cuenta que en el ejemplo siguiente, Foo simplemente asigna valores a las ranuras, algunas de las cuales son funciones. Por lo tanto, puede asignar distintas funciones a distintas instancias. En este ejemplo no hay creación de prototipos.
función px () { devuelve este prefijo + "X " ; } función Foo ( yz ) { this . prefijo = "a-" ; si ( yz > 0 ) { this . pyz = function () { devuelve this . prefijo + "Y" ; }; } de lo contrario { this . pyz = function () { devuelve this . prefijo + "Z" ; }; } this . m1 = px ; devuelve this ; } const foo1 = nuevo Foo ( 1 ); const foo2 = nuevo Foo ( 0 ); foo2 . prefijo = "b-" ; consola .log ( "foo1/2 " + foo1 .pyz () + foo2 .pyz ()); // foo1 / 2 aY bZ foo1 . m3 = px ; // Asigna la función en sí, no su resultado evaluado, es decir, no px() const baz = { "prefix" : "c-" }; baz . m4 = px ; // No es necesario un constructor para crear un objeto. consola .log ( "m1/m3/m4 " + foo1 .m1 () + foo1 .m3 ( ) + baz .m4 ( )); // m1 /m3/m4 aX aX cX foo1 . m2 (); // Lanza una excepción, porque foo1.m2 no existe.
Las funciones constructoras simplemente asignan valores a las ranuras de un objeto recién creado. Los valores pueden ser datos u otras funciones.
Ejemplo: Manipulación de un objeto:
función MiObjeto ( atributoA , atributoB ) { this . atributoA = atributoA ; this . atributoB = atributoB ; } MyObject . staticC = "azul" ; // En la función MyObject, no en el objeto console . log ( MyObject . staticC ); // azul const objeto = nuevo MiObjeto ( 'rojo' , 1000 ); consola . log ( objeto . atributo A ); // rojo consola . log ( objeto . atributo B ); // 1000 console.log ( object.staticC ) ; // indefinido object.atributoC = new Date ( ); // agregar una nueva propiedad eliminar objeto . atributoB ; // eliminar una propiedad del objeto console . log ( objeto . atributoB ); // indefinido
El constructor en sí se referencia en la ranura del constructor del prototipo del objeto . Por lo tanto,
function Foo () {} // El uso de 'new' establece ranuras de prototipo (por ejemplo, // x = new Foo() establecería el prototipo de x en Foo.prototype, // y Foo.prototype tiene una ranura de constructor que apunta a Foo). const x = new Foo (); // Lo anterior es casi equivalente a const y = {}; y . constructor = Foo ; y . constructor (); // Excepto x . constructor == y . constructor ; // verdadero x instanceof Foo ; // verdadero y instanceof Foo ; // falso // El prototipo de y es Object.prototype, no // Foo.prototype, ya que se inicializó con // {} en lugar de new Foo. // Aunque Foo está establecido en la ranura de constructor de y, // esto es ignorado por instanceof - solo se considera la ranura de constructor del prototipo de y .
Las funciones son objetos en sí mismas, que pueden utilizarse para producir un efecto similar a las "propiedades estáticas" (utilizando la terminología de C++/Java), como se muestra a continuación. (El objeto de función también tiene una prototype
propiedad especial, como se explica en la sección "Herencia" a continuación).
La eliminación de objetos rara vez se utiliza, ya que el motor de secuencias de comandos recolectará basura de los objetos a los que ya no se hace referencia.
JavaScript admite jerarquías de herencia a través de la creación de prototipos a la manera de Self .
En el siguiente ejemplo, la clase Derived hereda de la clase Base . Cuando se crea d como Derived , la referencia a la instancia base de Base se copia a d.base .
Derive no contiene un valor para aBaseFunction , por lo que se recupera de aBaseFunction cuando se accede a aBaseFunction . Esto se aclara al cambiar el valor de base.aBaseFunction , que se refleja en el valor de d.aBaseFunction .
Algunas implementaciones permiten acceder al prototipo o configurarlo explícitamente usando la ranura __proto__ como se muestra a continuación.
función Base () { this.anOverride = función ( ) { console.log ( " Base::anOverride()" ) ; } ; esto .aBaseFunction = función ( ) { console.log ( "Base :: aBaseFunction()" ); } ; } función Derivada ( ) { this.anOverride = función () { console.log ( " Derivada::anOverride()" ) ; } ; } const base = new Base ( ); Derived.prototype = base ; // Debe estar antes de new Derived() Derived.prototype.constructor = Derived ; // Requerido para que `instanceof` funcione const d = new Derived (); // Copia Derived.prototype en la ranura de prototipo oculta de la instancia d. d instanceof Derived ; // verdadero d instanceof Base ; // verdadero base . aBaseFunction = función () { console . log ( "Base::aNEWBaseFunction()" ); }; d . anOverride (); // Derivado::anOverride() d . aBaseFunction (); // Base::aNEWBaseFunction() console . log ( d . aBaseFunction == Derivado . prototipo . aBaseFunction ); // verdadero console . log ( d . __proto__ == base ); // verdadero en implementaciones basadas en Mozilla y falso en muchas otras.
A continuación se muestra claramente cómo se copian las referencias a los prototipos al crear una instancia, pero los cambios en un prototipo pueden afectar a todas las instancias que hacen referencia a él.
función m1 () { devuelve "Uno" ; } función m2 () { devuelve "Dos" ; } función m3 () { devuelve "Tres" ; } función Base () {} Base . prototipo . m = m2 ; const barra = new Base (); consola . log ( "barra. m " + bar . m ()); // barra. m Dos función Top ( ) { this.m = m3 ; } const t = new Top ( ); const foo = new Base ( ); Base.prototype = t ; // Sin efecto en foo, se copia la *referencia* a t. console.log ( "foo.m " + foo.m ( )) ; // foo.m Dos const baz = new Base (); console.log( " baz.m " + baz.m ( )); // baz.m Tres t . m = m1 ; // Afecta a baz y a cualquier otra clase derivada. console . log ( "baz.m1 " + baz . m ()); // baz.m1 Uno
En la práctica se utilizan muchas variaciones de estos temas, y pueden resultar al mismo tiempo potentes y confusos.
JavaScript incluye una declaración try ... catch ... finally
de manejo de excepciones para manejar errores en tiempo de ejecución.
La try ... catch ... finally
instrucción captura excepciones resultantes de un error o una instrucción throw. Su sintaxis es la siguiente:
try { // Declaraciones en las que se pueden generar excepciones } catch ( errorValue ) { // Declaraciones que se ejecutan en caso de una excepción } finally { // Declaraciones que se ejecutan posteriormente en cualquier caso }
Inicialmente, se ejecutan las instrucciones dentro del bloque try. Si se lanza una excepción, el flujo de control del script se transfiere inmediatamente a las instrucciones en el bloque catch, con la excepción disponible como argumento de error. De lo contrario, se omite el bloque catch. El bloque catch puede lanzar (errorValue) si no desea manejar un error específico.
En cualquier caso, las instrucciones del bloque finally siempre se ejecutan. Esto se puede utilizar para liberar recursos, aunque la memoria se recolecta automáticamente como basura.
Se puede omitir tanto la cláusula catch como la cláusula finally. El argumento catch es obligatorio.
La implementación de Mozilla permite múltiples sentencias catch, como una extensión del estándar ECMAScript. Siguen una sintaxis similar a la que se utiliza en Java :
try { declaración ; } catch ( e si e == "InvalidNameException" ) { declaración ; } catch ( e si e == "InvalidIdException" ) { declaración ; } catch ( e si e == "InvalidEmailException" ) { declaración ; } catch ( e ) { declaración ; }
En un navegador, el evento onerror se utiliza más comúnmente para atrapar excepciones.
onerror = función ( errorValue , url , lineNr ) {...; devuelve verdadero ;};
Evaluates the first parameter as an expression, which can include assignment statements. Variables local to functions can be referenced by the expression. However, eval
represents a major security risk, as it allows a bad actor to execute arbitrary code, so its use is discouraged.[20]
> (function foo() {... var x = 7;... console.log("val " + eval("x + 2"));... })();val 9undefined
Omitting semicolons is not a good programming practice; you should get into the habit of inserting them.
In JavaScript, a variable can be declared after it has been used. In other words; a variable can be used before it has been declared.