Paradigma | impulsado por eventos, funcional, imperativo |
---|---|
Diseñada por | Brendan Eich de Netscape inicialmente; otros también han contribuido al estándar ECMAScript |
Apareció por primera vez | 4 de diciembre de 1995 ; Hace 25 años (4 de diciembre de 1995) |
Lanzamiento estable | ECMAScript 2021 ![]() |
Versión de vista previa | ECMAScript 2022/22 ![]() |
Disciplina de mecanografía | Dinámico, débil, pato |
Extensiones de nombre de archivo |
|
Sitio web | www.ecma-international.org / publications-and-standards / standards / ecma-262 / |
Implementaciones importantes | |
V8, JavaScriptCore, SpiderMonkey, Chakra | |
Influenciado por | |
Java, esquema, AWK, HyperTalk | |
Influenciado | |
TypeScript, CoffeeScript, AssemblyScript, ActionScript, Dart, Objective-J, Opa, Haxe | |
|
JavaScript ( / dʒ ɑː v ə ˌ s k r ɪ p t / ), a menudo abreviado como JS, es un lenguaje de programación que se ajusta a la ECMAScript especificación. JavaScript es de alto nivel, a menudo compilado justo a tiempo y de múltiples paradigmas. Tiene sintaxis entre corchetes, escritura dinámica, orientación a objetos basada en prototipos y funciones de primera clase.
Junto con HTML y CSS, JavaScript es una de las tecnologías centrales de la World Wide Web. Más del 97% de los sitios web lo utilizan del lado del cliente para el comportamiento de las páginas web, a menudo incorporando bibliotecas de terceros. La mayoría de los navegadores web tienen un motor JavaScript dedicado para ejecutar el código en el dispositivo del usuario.
Como lenguaje de múltiples paradigmas, JavaScript admite estilos de programación imperativos, funcionales y controlados por eventos. Tiene interfaces de programación de aplicaciones (API) para trabajar con texto, fechas, expresiones regulares, estructuras de datos estándar y el Modelo de objetos de documento (DOM).
El estándar ECMAScript no incluye ninguna entrada / salida (E / S), como redes, almacenamiento o instalaciones gráficas. En la práctica, el navegador web u otro sistema de ejecución proporciona API de JavaScript para E / S.
Los motores de JavaScript se usaban originalmente solo en navegadores web, pero ahora son componentes centrales de otros sistemas de software, sobre todo servidores y una variedad de aplicaciones.
Aunque existen similitudes entre JavaScript y Java, incluido el nombre del lenguaje, la sintaxis y las respectivas bibliotecas estándar, los dos lenguajes son distintos y difieren mucho en diseño.
El navegador web Mosaic se lanzó en 1993. Como primer navegador con una interfaz gráfica de usuario accesible para personas sin conocimientos técnicos, jugó un papel destacado en el rápido crecimiento de la naciente World Wide Web. Los desarrolladores principales de Mosaic fundaron la corporación Netscape, que lanzó un navegador más refinado, Netscape Navigator, en 1994. Navigator se convirtió rápidamente en el navegador más utilizado.
Durante estos años de formación de la Web, las páginas web solo podían ser estáticas y carecían de la capacidad de comportamiento dinámico después de que la página se cargara en el navegador. Había un deseo en la floreciente escena del desarrollo web de eliminar esta limitación, por lo que en 1995, Netscape decidió agregar un lenguaje de programación a Navigator. Siguieron dos rutas para lograrlo: colaborar con Sun Microsystems para integrar el lenguaje de programación Java, y al mismo tiempo contratar a Brendan Eich para integrar el lenguaje Scheme.
La gerencia de Netscape pronto decidió que la mejor opción era que Eich diseñara un nuevo lenguaje, con una sintaxis similar a Java y menos a Scheme u otros lenguajes de scripting existentes. Aunque el nuevo lenguaje y su implementación de intérprete se llamaron LiveScript cuando se envió por primera vez como parte de una versión beta de Navigator en septiembre de 1995, el nombre se cambió a JavaScript para el lanzamiento oficial en diciembre. Eich afirma que la sintaxis de HyperTalk y los nombres de los controladores influyeron en JavaScript.
La elección del nombre de JavaScript ha causado confusión, lo que implica que está directamente relacionado con Java. Dado que Java era el nuevo lenguaje de programación de moda en ese momento, Netscape lo ha caracterizado como una estrategia de marketing para dar su propio y nuevo prestigio al lenguaje.
Microsoft debutó con Internet Explorer en 1995, lo que provocó una guerra de navegadores con Netscape. En el frente de JavaScript, Microsoft realizó ingeniería inversa del intérprete Navigator para crear el suyo, llamado JScript.
JScript se lanzó por primera vez en 1996, junto con el soporte inicial para CSS y extensiones para HTML. Cada una de estas implementaciones fue notablemente diferente de sus contrapartes en Navigator. Estas diferencias dificultaron que los desarrolladores hicieran que sus sitios web funcionaran bien en ambos navegadores, lo que llevó a un uso generalizado de los logotipos de "mejor visto en Netscape" y "mejor visto en Internet Explorer" durante varios años.
En noviembre de 1996, Netscape envió JavaScript a Ecma International, como punto de partida para una especificación estándar que todos los proveedores de navegadores podrían cumplir. Esto llevó al lanzamiento oficial de la primera especificación del lenguaje ECMAScript en junio de 1997.
El proceso de estándares continuó durante algunos años, con el lanzamiento de ECMAScript 2 en junio de 1998 y ECMAScript 3 en diciembre de 1999. El trabajo en ECMAScript 4 comenzó en 2000.
Mientras tanto, Microsoft ganó una posición cada vez más dominante en el mercado de los navegadores. A principios de la década de 2000, la participación de mercado de Internet Explorer alcanzó el 95%. Esto significó que JScript se convirtió en el estándar de facto para las secuencias de comandos del lado del cliente en la Web.
Microsoft participó inicialmente en el proceso de estándares e implementó algunas propuestas en su lenguaje JScript, pero finalmente dejó de colaborar en el trabajo de Ecma. Por lo tanto, ECMAScript 4 fue suspendido.
Durante el período de dominio de Internet Explorer a principios de la década de 2000, las secuencias de comandos del lado del cliente estaban estancadas. Esto comenzó a cambiar en 2004, cuando el sucesor de Netscape, Mozilla, lanzó el navegador Firefox. Firefox fue bien recibido por muchos y le quitó una participación de mercado significativa a Internet Explorer.
En 2005, Mozilla se unió a ECMA International y comenzó a trabajar en el estándar ECMAScript para XML (E4X). Esto llevó a Mozilla a trabajar en conjunto con Macromedia (luego adquirida por Adobe Systems ), quienes estaban implementando E4X en su lenguaje ActionScript 3, que estaba basado en un borrador de ECMAScript 4. El objetivo se convirtió en estandarizar ActionScript 3 como el nuevo ECMAScript 4. Con este fin, Adobe Systems lanzó la implementación de Tamarin como un proyecto de código abierto. Sin embargo, Tamarin y ActionScript 3 eran demasiado diferentes de las secuencias de comandos del lado del cliente establecidas, y sin la cooperación de Microsoft, ECMAScript 4 nunca llegó a buen término.
Mientras tanto, se estaban produciendo desarrollos muy importantes en comunidades de código abierto no afiliadas al trabajo de ECMA. En 2005, Jesse James Garrett publicó un documento técnico en el que acuñó el término Ajax y describió un conjunto de tecnologías, de las cuales JavaScript era la columna vertebral, para crear aplicaciones web donde los datos se pueden cargar en segundo plano, evitando la necesidad de una página completa. recarga. Esto provocó un período de renacimiento de JavaScript, encabezado por bibliotecas de código abierto y las comunidades que se formaron a su alrededor. Se crearon muchas bibliotecas nuevas, incluidas jQuery, Prototype, Dojo Toolkit y MooTools.
Google debutó con su navegador Chrome en 2008, con el motor JavaScript V8 que era más rápido que su competencia. La innovación clave fue la compilación justo a tiempo (JIT), por lo que otros proveedores de navegadores necesitaban reacondicionar sus motores para JIT.
En julio de 2008, estos partidos dispares se reunieron para una conferencia en Oslo. Esto condujo al eventual acuerdo a principios de 2009 para combinar todo el trabajo relevante e impulsar el idioma. El resultado fue el estándar ECMAScript 5, lanzado en diciembre de 2009.
En 2009, Ryan Dahl lanzó la primera versión de Node.js, que combinaba el motor V8 de Google, un bucle de eventos y una API de E / S de bajo nivel para proporcionar un entorno completo de programación de JavaScript basado en eventos y del lado del servidor. Esto simplificó el intercambio de datos entre el código del lado del cliente y del servidor, lo que permitió a los desarrolladores web con experiencia en JavaScript del lado del cliente transferir sus habilidades al desarrollo del lado del servidor. Esto finalmente resultó en una comunidad de varios millones de desarrolladores, así como en npm, el registro de paquetes de software más grande del mundo.
El trabajo ambicioso en el lenguaje continuó durante varios años, que culminó con una extensa colección de adiciones y mejoras que se formalizaron con la publicación de ECMAScript 6 en 2015.
El borrador de la especificación se mantiene actualmente abiertamente en GitHub, y las ediciones de ECMAScript se producen a través de instantáneas anuales regulares. Las posibles revisiones del lenguaje se examinan a través de un proceso de propuesta integral. Ahora, en lugar de los números de edición, los desarrolladores verifican el estado de las próximas funciones de forma individual.
El ecosistema de JavaScript actual tiene muchas bibliotecas y marcos, prácticas de programación establecidas y un mayor uso de JavaScript fuera de los navegadores web. Además, con el auge de las aplicaciones de una sola página y otros sitios web con mucho JavaScript, se han creado varios transpilers para ayudar al proceso de desarrollo.
"JavaScript" es una marca comercial de Oracle Corporation en los Estados Unidos.
JavaScript es el lenguaje de programación del lado del cliente dominante en la Web, y el 97% de los sitios web lo utilizan para este propósito. Los scripts están incrustados o incluidos en documentos HTML e interactúan con el DOM. La mayoría de los navegadores web, incluida la gran mayoría de Android y todos los navegadores de iPad, tienen un motor JavaScript integrado que ejecuta el código en el dispositivo del usuario.
Más del 80% de los sitios web utilizan una biblioteca JavaScript o un marco web de terceros para sus scripts del lado del cliente.
jQuery es, con mucho, la biblioteca más popular, utilizada por más del 75% de los sitios web. Facebook creó la biblioteca React para su sitio web y luego la lanzó como código abierto ; otros sitios, incluido Twitter, ahora lo usan. Del mismo modo, el marco Angular creado por Google para sus sitios web, incluidos YouTube y Gmail, ahora es un proyecto de código abierto utilizado por otros.
Por el contrario, el término "Vanilla JS" se ha acuñado para los sitios web que no utilizan bibliotecas o marcos, sino que se basan por completo en la funcionalidad estándar de JavaScript.
El uso de JavaScript se ha expandido más allá de las raíces de su navegador web. Los motores de JavaScript ahora están integrados en una variedad de otros sistemas de software, tanto para implementaciones de sitios web del lado del servidor como para aplicaciones que no son de navegador.
Los primeros intentos de promover el uso del lado del servidor JavaScript eran Netscape Enterprise Server y Microsoft 's Internet Information Services, pero eran pequeños nichos. El uso del lado del servidor finalmente comenzó a crecer a fines de la década de 2000, con la creación de Node.js y otros enfoques.
Electron, Cordova, React Native y otros marcos de aplicaciones se han utilizado para crear muchas aplicaciones con comportamiento implementado en JavaScript. Otras aplicaciones que no son de navegador incluyen compatibilidad con Adobe Acrobat para la creación de scripts de documentos PDF y extensiones de GNOME Shell escritas en JavaScript.
JavaScript ha comenzado a aparecer recientemente en algunos sistemas integrados, generalmente aprovechando Node.js.
Las siguientes características son comunes a todas las implementaciones conformes de ECMAScript, a menos que se especifique explícitamente lo contrario.
JavaScript admite gran parte de la sintaxis de programación estructurada de C (por ejemplo, if
declaraciones, while
bucles, switch
declaraciones, do while
bucles, etc.). Una excepción parcial es el alcance : originalmente, JavaScript solo tenía el alcance de la función con var
; luego se agregó el alcance del bloque en ECMAScript 2015 con las palabras clave let
y const
. Como C, JavaScript hace una distinción entre expresiones y declaraciones. Una diferencia sintáctica de C es la inserción automática de punto y coma, que permite omitir los puntos y comas (que terminan las declaraciones).
JavaScript tiene un tipo débil, lo que significa que ciertos tipos se emiten implícitamente según la operación utilizada.
+
operador binario convierte ambos operandos en una cadena a menos que ambos operandos sean números. Esto se debe a que el operador de suma funciona como operador de concatenación.-
operador binario siempre convierte ambos operandos a un número+
, -
) siempre convierten el operando en un númeroLos valores se convierten en cadenas como las siguientes:
,
)[object Object]
donde Object
es el nombre del constructor del objeto.Los valores se convierten en números convirtiéndolos en cadenas y luego convirtiendo las cadenas en números. Estos procesos se pueden modificar definiendo toString
y valueOf
funciones en el prototipo para la fundición de cadenas y números, respectivamente.
JavaScript ha recibido críticas por la forma en que implementa estas conversiones, ya que la complejidad de las reglas puede confundirse con inconsistencias. Por ejemplo, al agregar un número a una cadena, el número se convertirá en una cadena antes de realizar la concatenación, pero al restar un número de una cadena, la cadena se convertirá en un número antes de realizar la resta.
operando izquierdo | operador | operando derecho | resultado |
---|---|---|---|
[] (matriz vacía) | + | [] (matriz vacía) | "" (cuerda vacía) |
[] (matriz vacía) | + | {} (objeto vacío) | "[object Object]" (cuerda) |
false (booleano) | + | [] (matriz vacía) | "false" (cuerda) |
"123" (cuerda) | + | 1 (número) | "1231" (cuerda) |
"123" (cuerda) | - | 1 (número) | 122 (número) |
A menudo también se menciona que {} + []
resulta en 0
(número). Esto es engañoso: {}
se interpreta como un bloque de código vacío en lugar de un objeto vacío, y el +
operador unario restante convierte la matriz vacía en un número. Si envuelve la expresión entre paréntesis, ({} + [])
las llaves se interpretan como un objeto vacío y el resultado de la expresión es el "[object Object]"
esperado.
eval
función que puede ejecutar declaraciones proporcionadas como cadenas en tiempo de ejecución.La herencia prototípica en JavaScript es descrita por Douglas Crockford como:
Hace prototipos de objetos y luego... crea nuevas instancias. Los objetos son mutables en JavaScript, por lo que podemos aumentar las nuevas instancias, dándoles nuevos campos y métodos. Estos pueden actuar como prototipos para objetos incluso más nuevos. No necesitamos clases para hacer muchos objetos similares... Los objetos heredan de los objetos. ¿Qué podría estar más orientado a objetos que eso?
En JavaScript, un objeto es una matriz asociativa, aumentada con un prototipo (ver más abajo); cada clave proporciona el nombre de una propiedad de objeto, y hay dos formas sintácticas de especificar dicho nombre: notación de puntos ( obj.x = 10
) y notación de corchetes ( obj['x'] = 10
). Una propiedad puede agregarse, recuperarse o eliminarse en tiempo de ejecución. La mayoría de las propiedades de un objeto (y cualquier propiedad que pertenezca a la cadena de herencia del prototipo de un objeto) se pueden enumerar mediante un for...in
bucle.
Object
prototipo). ECMAScript 5 ofrece el Object.create
método, lo que permite la creación explícita de una instancia sin heredar automáticamente del Object
prototipo (los entornos más antiguos pueden asignar el prototipo null
). La prototype
propiedad del constructor determina el objeto utilizado para el prototipo interno del nuevo objeto. Se pueden agregar nuevos métodos modificando el prototipo de la función utilizada como constructor. Los constructores integrados de JavaScript, como Array
o Object
, también tienen prototipos que se pueden modificar. Si bien es posible modificar el Object
prototipo, generalmente se considera una mala práctica porque la mayoría de los objetos en JavaScript heredarán métodos y propiedades del Object
prototipo, y es posible que no esperen que se modifique el prototipo.Una función es de primera clase ; una función se considera un objeto. Como tal, una función puede tener propiedades y métodos, como .call()
y .bind()
. Una función anidada es una función definida dentro de otra función. Se crea cada vez que se invoca la función externa. Además, cada función anidada forma un cierre léxico : el alcance léxico de la función externa (incluida cualquier constante, variable local o valor de argumento) se convierte en parte del estado interno de cada objeto de función interna, incluso después de que concluye la ejecución de la función externa.. JavaScript también admite funciones anónimas.
JavaScript admite la delegación implícita y explícita.
this
palabra clave dentro de su function
cuerpo. Luego, un rol debe delegarse explícitamente a través de call
o apply
en objetos que deben presentar un comportamiento adicional que no se comparte a través de la cadena de prototipos.JS es un lenguaje de índice cero.
lt;scriptgt;
). Esta no es una característica del lenguaje per se, pero es común en la mayoría de las implementaciones de JavaScript. JavaScript procesa los mensajes de una cola de uno en uno. JavaScript llama a una función asociada con cada mensaje nuevo, creando un marco de pila de llamadas con los argumentos de la función y las variables locales. La pila de llamadas se reduce y crece según las necesidades de la función. Cuando la pila de llamadas está vacía al finalizar la función, JavaScript pasa al siguiente mensaje de la cola. Esto se denomina bucle de eventos y se describe como "ejecutar hasta el final" porque cada mensaje se procesa por completo antes de que se considere el siguiente. Sin embargo, el modelo de concurrencia del lenguaje describe el bucle de eventos como sin bloqueo : la entrada / salida del programa se realiza mediante eventos y funciones de devolución de llamada. Esto significa, por ejemplo, que JavaScript puede procesar un clic del mouse mientras espera que una consulta de la base de datos devuelva información.arguments
objeto local. Las funciones variables también se pueden crear utilizando el bind
método.Históricamente, algunos motores de JavaScript admitían estas funciones no estándar:
catch
cláusulas condicionales (como Java)function(args) expr
; esta sintaxis experimental es anterior a las funciones de flecha) Las variables en JavaScript se pueden definir utilizando las palabras clave var
, let
o const
.
// Declares a function-scoped variable named `x`, and implicitly assigns the // special value `undefined` to it. Variables without value are automatically // set to undefined. var x; // Variables can be manually set to `undefined` like so var x2 = undefined; // Declares a block-scoped variable named `y`, and implicitly sets it to // `undefined`. The `let` keyword was introduced in ECMAScript 2015. let y; // Declares a block-scoped, un-reassignable variable named `z`, and sets it to // a string literal. The `const` keyword was also introduced in ECMAScript 2015, // and must be explicitly assigned to. // The keyword `const` means constant, hence the variable cannot be reassigned // as the value is `constant`. const z = "this value cannot be reassigned!"; // Declares a variable named `myNumber`, and assigns a number literal (the value // `2`) to it. let myNumber = 2; // Reassigns `myNumber`, setting it to a string literal (the value `"foo"`). // JavaScript is a dynamically-typed language, so this is legal. myNumber = "foo";
Tenga en cuenta los comentarios en el ejemplo anterior, todos los cuales fueron precedidos por dos barras diagonales.
No hay una funcionalidad de entrada / salida incorporada en JavaScript; el entorno de tiempo de ejecución lo proporciona. La especificación ECMAScript en la edición 5.1 menciona:
de hecho, no existen disposiciones en esta especificación para la entrada de datos externos o la salida de resultados calculados.
Sin embargo, la mayoría de los entornos de ejecución tienen un console
objeto que se puede utilizar para imprimir la salida. Aquí hay un programa Hello World minimalista en JavaScript:
console.log("Hello World!");
Una función recursiva simple:
function factorial(n) { if (n === 0) return 1; // 0! = 1 return n * factorial(n - 1); } factorial(3); // returns 6
Una función anónima (o lambda):
function counter() { let count = 0; return function() { return ++count; }; } let closure = counter(); closure(); // returns 1 closure(); // returns 2 closure(); // returns 3
Este ejemplo muestra que, en JavaScript, los cierres de funciones capturan sus variables no locales por referencia.
Las funciones de flecha se introdujeron por primera vez en la sexta edición: ECMAScript 2015. Acortan la sintaxis para escribir funciones en JavaScript. Las funciones de flecha son de naturaleza anónima; se necesita una variable para hacer referencia a ellos para poder invocarlos después de su creación.
Ejemplo de función de flecha:
// Arrow functions let us omit the `function` keyword. // Here `long_example` points to an anonymous function value. const long_example = (input1, input2) =gt; { console.log("Hello, World!"); const output = input1 + input2; return output; }; // If there are no braces, the arrow function simply returns the expression // So here it's (input1 + input2) const short_example = (input1, input2) =gt; input1 + input2; long_example(2, 3); // Prints "Hello, World!" and returns 5 short_example(2, 5); // Returns 7 // If an arrow function only has one parameter, the parentheses can be removed. const no_parentheses = input =gt; input + 2; no_parentheses(3); // Returns 5
En JavaScript, los objetos se crean de la misma forma que las funciones; esto se conoce como un objeto de función.
Ejemplo de objeto:
function Ball(r) { this.radius = r; // the "r" argument is local to the ball object this.area = Math.PI * (r ** 2); // parentheses don't do anything but clarify // objects can contain functions ("method") this.show = function() { drawCircle(this.radius); // references another function (that draws a circle) }; } let myBall = new Ball(5); // creates a new instance of the ball object with radius 5 myBall.radius++; // object properties can usually be modified from the outside myBall.show(); // using the inherited "show" function
Demostración de función variádica ( arguments
es una variable especial):
function sum() { let x = 0; for (let i = 0; i lt; arguments.length; ++i) x += arguments[i]; return x; } sum(1, 2); // returns 3 sum(1, 2, 3); // returns 6
Las expresiones de función invocadas inmediatamente se utilizan a menudo para crear cierres. Los cierres permiten recopilar propiedades y métodos en un espacio de nombres y hacer que algunos de ellos sean privados:
let counter = (function() { let i = 0; // private property return { // public methods get: function() { alert(i); }, set: function(value) { i = value; }, increment: function() { alert(++i); } }; })(); // module counter.get(); // shows 0 counter.set(6); counter.increment(); // shows 7 counter.increment(); // shows 8
Exportación e importación de módulos en JavaScript
Ejemplo de exportación:
/* mymodule.js */ // This function remains private, as it is not exported let sum = (a, b) =gt; { return a + b; } // Export variables export let name = 'Alice'; export let age = 23; // Export named functions export function add(num1, num2) { return num1 + num2; } // Export class export class Multiplication { constructor(num1, num2) { this.num1 = num1; this.num2 = num2; } add() { return sum(this.num1, this.num2); } }
Ejemplo de importación:
// Import one property import { add } from './mymodule.js'; console.log(add(1, 2)); // 3 // Import multiple properties import { name, age } from './mymodule.js'; console.log(name, age); //gt; "Alice", 23 // Import all properties from a module import * from './module.js' console.log(name, age); //gt; "Alice", 23 console.log(add(1,2)); //gt; 3
Este código de muestra muestra varias funciones de JavaScript.
/* Finds the lowest common multiple (LCM) of two numbers */ function LCMCalculator(x, y) { // constructor function let checkInt = function(x) { // inner function if (x % 1 !== 0) throw new TypeError(x + "is not an integer"); // var a = mouseX return x; }; this.a = checkInt(x) // semicolons ^^^^ are optional, a newline is enough this.b = checkInt(y); } // The prototype of object instances created by a constructor is // that constructor's "prototype" property. LCMCalculator.prototype = { // object literal constructor: LCMCalculator, // when reassigning a prototype, set the constructor property appropriately gcd: function() { // method that calculates the greatest common divisor // Euclidean algorithm: let a = Math.abs(this.a), b = Math.abs(this.b), t; if (a lt; b) { // swap variables // t = b; b = a; a = t; [a, b] = [b, a]; // swap using destructuring assignment (ES6) } while (b !== 0) { t = b; b = a % b; a = t; } // Only need to calculate GCD once, so "redefine" this method. // (Actually not redefinition—it's defined on the instance itself, // so that this.gcd refers to this "redefinition" instead of LCMCalculator.prototype.gcd. // Note that this leads to a wrong result if the LCMCalculator object members "a" and/or "b" are altered afterwards.) // Also, 'gcd' === "gcd", this['gcd'] === this.gcd this['gcd'] = function() { return a; }; return a; }, // Object property names can be specified by strings delimited by double (") or single (') quotes. lcm: function() { // Variable names do not collide with object properties, e.g., |lcm| is not |this.lcm|. // not using |this.a*this.b| to avoid FP precision issues let lcm = this.a / this.gcd() * this.b; // Only need to calculate lcm once, so "redefine" this method. this.lcm = function() { return lcm; }; return lcm; }, toString: function() { return "LCMCalculator: a = " + this.a + ", b = " + this.b; } }; // Define generic output function; this implementation only works for Web browsers function output(x) { document.body.appendChild(document.createTextNode(x)); document.body.appendChild(document.createElement('br')); } // Note: Array's map() and forEach() are defined in JavaScript 1.6. // They are used here to demonstrate JavaScript's inherent functional nature. [ [25, 55], [21, 56], [22, 58], [28, 56] ].map(function(pair) { // array literal + mapping function return new LCMCalculator(pair[0], pair[1]); }).sort((a, b) =gt; a.lcm() - b.lcm()) // sort with this comparative function; =gt; is a shorthand form of a function, called "arrow function".forEach(printResult); function printResult(obj) { output(obj + ", gcd = " + obj.gcd() + ", lcm = " + obj.lcm()); }
La siguiente salida debería mostrarse en la ventana del navegador.
LCMCalculator: a = 28, b = 56, gcd = 28, lcm = 56 LCMCalculator: a = 21, b = 56, gcd = 7, lcm = 168 LCMCalculator: a = 25, b = 55, gcd = 5, lcm = 275 LCMCalculator: a = 22, b = 58, gcd = 2, lcm = 638
JavaScript y DOM brindan la posibilidad de que los autores malintencionados entreguen scripts para que se ejecuten en una computadora cliente a través de la Web. Los autores de navegadores minimizan este riesgo mediante dos restricciones. Primero, los scripts se ejecutan en una caja de arena en la que solo pueden realizar acciones relacionadas con la Web, no tareas de programación de propósito general como crear archivos. En segundo lugar, las secuencias de comandos están restringidas por la política del mismo origen : las secuencias de comandos de un sitio web no tienen acceso a información como nombres de usuario, contraseñas o cookies enviadas a otro sitio. La mayoría de los errores de seguridad relacionados con JavaScript son infracciones de la misma política de origen o de la zona de pruebas.
Hay subconjuntos de JavaScript general (ADsafe, Secure ECMAScript (SES)) que brindan mayores niveles de seguridad, especialmente en el código creado por terceros (como anuncios). Closure Toolkit es otro proyecto para la incrustación segura y el aislamiento de JavaScript y HTML de terceros.
La Política de seguridad de contenido es el principal método previsto para garantizar que solo se ejecute código de confianza en una página web.
Ver también: Política de seguridad de contenidoUn problema de seguridad común relacionado con JavaScript es la secuencia de comandos entre sitios (XSS), una violación de la política del mismo origen. Las vulnerabilidades XSS ocurren cuando un atacante puede hacer que un sitio web objetivo, como un sitio web de banca en línea, incluya un script malicioso en la página web presentada a la víctima. El script en este ejemplo puede acceder a la aplicación bancaria con los privilegios de la víctima, potencialmente revelando información secreta o transfiriendo dinero sin la autorización de la víctima. Una solución a las vulnerabilidades XSS es utilizar el escape HTML siempre que se muestren datos que no sean de confianza.
Algunos navegadores incluyen protección parcial contra ataques XSS reflejados, en los que el atacante proporciona una URL que incluye un script malicioso. Sin embargo, incluso los usuarios de esos navegadores son vulnerables a otros ataques XSS, como aquellos en los que el código malicioso se almacena en una base de datos. Solo el diseño correcto de las aplicaciones web en el lado del servidor puede evitar completamente XSS.
Las vulnerabilidades XSS también pueden ocurrir debido a errores de implementación por parte de los autores del navegador.
Otra vulnerabilidad entre sitios es la falsificación de solicitudes entre sitios (CSRF). En CSRF, el código en el sitio de un atacante engaña al navegador de la víctima para que realice acciones que el usuario no pretendía en un sitio de destino (como transferir dinero en un banco). Cuando los sitios de destino dependen únicamente de las cookies para la autenticación de solicitudes, las solicitudes que se originan a partir del código del sitio del atacante pueden llevar las mismas credenciales de inicio de sesión válidas del usuario que las inició. En general, la solución para CSRF es requerir un valor de autenticación en un campo de formulario oculto, y no solo en las cookies, para autenticar cualquier solicitud que pueda tener efectos duraderos. También puede resultar útil comprobar el encabezado HTTP Referrer.
El "secuestro de JavaScript" es un tipo de ataque CSRF en el que una lt;scriptgt;
etiqueta en el sitio de un atacante explota una página del sitio de la víctima que devuelve información privada como JSON o JavaScript. Las posibles soluciones incluyen:
Los desarrolladores de aplicaciones cliente-servidor deben reconocer que los clientes que no son de confianza pueden estar bajo el control de atacantes. El autor de la aplicación no puede asumir que su código JavaScript se ejecutará según lo previsto (o en absoluto) porque un adversario determinado podría extraer cualquier secreto incrustado en el código. Algunas implicaciones son:
Los sistemas de gestión de paquetes como npm y Bower son populares entre los desarrolladores de JavaScript. Dichos sistemas permiten a un desarrollador administrar fácilmente las dependencias de su programa en las bibliotecas de programas de otros desarrolladores. Los desarrolladores confían en que los encargados de las bibliotecas las mantendrán seguras y actualizadas, pero no siempre es así. Ha surgido una vulnerabilidad debido a esta confianza ciega. Las bibliotecas confiables pueden tener nuevas versiones que provoquen la aparición de errores o vulnerabilidades en todos los programas que dependen de las bibliotecas. A la inversa, una biblioteca puede quedar sin parches con vulnerabilidades conocidas en la naturaleza. En un estudio realizado con una muestra de 133.000 sitios web, los investigadores encontraron que el 37% de los sitios web incluían una biblioteca con al menos una vulnerabilidad conocida. "El retraso medio entre la versión de biblioteca más antigua utilizada en cada sitio web y la versión más nueva disponible de esa biblioteca es de 1.177 días en ALEXA, y el desarrollo de algunas bibliotecas que todavía están en uso activo cesó hace años". Otra posibilidad es que el responsable de mantenimiento de una biblioteca elimine la biblioteca por completo. Esto ocurrió en marzo de 2016 cuando Azer Koçulu eliminó su repositorio de npm. Esto provocó la rotura de decenas de miles de programas y sitios web que dependían de sus bibliotecas.
JavaScript proporciona una interfaz para una amplia gama de capacidades del navegador, algunas de las cuales pueden tener fallas, como desbordamientos de búfer. Estas fallas pueden permitir a los atacantes escribir scripts que ejecutarían cualquier código que deseen en el sistema del usuario. Este código no está limitado de ninguna manera a otra aplicación JavaScript. Por ejemplo, una vulnerabilidad de saturación del búfer puede permitir que un atacante obtenga acceso a la API del sistema operativo con privilegios de superusuario.
Estas fallas han afectado a los principales navegadores, incluidos Firefox, Internet Explorer y Safari.
Los complementos, como los reproductores de video, Adobe Flash y la amplia gama de controles ActiveX habilitados de forma predeterminada en Microsoft Internet Explorer, también pueden tener fallas explotables a través de JavaScript (tales fallas se han aprovechado en el pasado).
En Windows Vista, Microsoft ha intentado contener los riesgos de errores, como desbordamientos de búfer, ejecutando el proceso de Internet Explorer con privilegios limitados. De manera similar, Google Chrome limita sus procesadores de páginas a su propia "caja de arena".
Los navegadores web pueden ejecutar JavaScript fuera de la zona de pruebas, con los privilegios necesarios para, por ejemplo, crear o eliminar archivos. Dichos privilegios no están destinados a otorgarse al código de la Web.
La concesión incorrecta de privilegios a JavaScript desde la Web ha influido en las vulnerabilidades de Internet Explorer y Firefox. En Windows XP Service Pack 2, Microsoft degradó los privilegios de JScript en Internet Explorer.
Microsoft Windows permite que los archivos de origen JavaScript en el disco duro de una computadora se inicien como programas de uso general que no sean de espacio aislado (consulte: Windows Script Host ). Esto hace que JavaScript (como VBScript ) sea un vector teóricamente viable para un caballo de Troya, aunque los caballos de Troya JavaScript son poco comunes en la práctica.
En 2015, investigadores de seguridad describieron en un documento una implementación de prueba de concepto basada en JavaScript de un ataque de martillo de hilera.
En 2017, se demostró un ataque basado en JavaScript a través del navegador que podía eludir ASLR. Se llama "ASLR⊕Cache" o AnC.
En 2018, el documento que anunció los ataques Spectre contra la ejecución especulativa en Intel y otros procesadores incluía una implementación de JavaScript.
Han evolucionado herramientas importantes con el lenguaje.
Un error común es que JavaScript es similar o está estrechamente relacionado con Java. Es cierto que ambos tienen una sintaxis similar a C (siendo el lenguaje C su lenguaje ancestro común más inmediato). También suelen estar en un espacio aislado (cuando se usan dentro de un navegador), y JavaScript se diseñó teniendo en cuenta la sintaxis y la biblioteca estándar de Java. En particular, todas las palabras clave de Java se reservaron en JavaScript original, la biblioteca estándar de JavaScript sigue las convenciones de nomenclatura de Java, y JavaScript Math
y los Date
objetos se basan en clases de Java 1.0, pero las similitudes terminan ahí.
Tanto Java como JavaScript aparecieron por primera vez en 1995, pero Java fue desarrollado por James Gosling de Sun Microsystems y JavaScript por Brendan Eich de Netscape Communications.
Las diferencias entre los dos idiomas son más prominentes que sus similitudes. Java tiene escritura estática, mientras que la escritura de JavaScript es dinámica. Java se carga desde un código de bytes compilado, mientras que JavaScript se carga como código fuente legible por humanos. Los objetos de Java están basados en clases, mientras que los de JavaScript están basados en prototipos. Finalmente, Java no admitió la programación funcional hasta Java 8, mientras que JavaScript lo ha hecho desde el principio, siendo influenciado por Scheme.
JSON, o JavaScript Object Notation, es un formato de intercambio de datos de uso general que se define como un subconjunto de la sintaxis literal de objetos de JavaScript.
Desde 2017, los navegadores web han admitido WebAssembly, un formato binario que permite que un motor JavaScript ejecute partes críticas para el rendimiento de los scripts de páginas web cerca de la velocidad nativa. El código de WebAssembly se ejecuta en el mismo espacio aislado que el código JavaScript normal.
asm.js es un subconjunto de JavaScript que sirvió como precursor de WebAssembly.
JavaScript es el lenguaje del lado del cliente dominante en la Web, y muchos sitios web tienen muchos scripts. Por lo tanto, se han creado transpilers para convertir código escrito en otros lenguajes, lo que puede ayudar al proceso de desarrollo.