ventajas ultima paginas español ejemplos desventajas descargar definicion caracteristicas javascript

paginas - ultima version de javascript



¿Cuál es la explicación de estos comportamientos de JavaScript extraños mencionados en la charla ''Wat'' para CodeMash 2012? (5)

La charla de ''Wat'' para CodeMash 2012 básicamente señala algunas peculiaridades extrañas con Ruby y JavaScript.

He hecho un JSFiddle de los resultados en http://jsfiddle.net/fe479/9/ .

Los comportamientos específicos de JavaScript (como no sé Ruby) se enumeran a continuación.

Encontré en el JSFiddle que algunos de mis resultados no correspondían con los del video, y no estoy seguro de por qué Sin embargo, tengo curiosidad por saber cómo maneja JavaScript el trabajo entre bastidores en cada caso.

Empty Array + Empty Array [] + [] result: <Empty String>

Tengo bastante curiosidad por el operador + cuando se utiliza con matrices en JavaScript. Esto coincide con el resultado del video.

Empty Array + Object [] + {} result: [Object]

Esto coincide con el resultado del video. ¿Que está pasando aqui? ¿Por qué es esto un objeto. ¿Qué hace el operador + ?

Object + Empty Array {} + [] result [Object]

Esto no coincide con el video. El video sugiere que el resultado es 0, mientras que obtengo [Objeto].

Object + Object {} + {} result: [Object][Object]

Esto tampoco coincide con el video, y ¿cómo se traduce una variable en dos objetos? Tal vez mi JSFiddle está mal.

Array(16).join("wat" - 1) result: NaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaNNaN

Haciendo wat + 1 resulta en wat1wat1wat1wat1 ...

Sospecho que este es solo un comportamiento directo que al intentar restar un número de una cadena da como resultado NaN.


Aquí hay una lista de explicaciones de los resultados que está viendo (y que se supone que debe ver). Las referencias que estoy usando son del estándar ECMA-262 .

  1. [] + []

    Cuando se usa el operador de suma, los operandos izquierdo y derecho se convierten primero a primitivos ( §11.6.1 ). Según §9.1 , la conversión de un objeto (en este caso una matriz) a una primitiva devuelve su valor predeterminado, que para los objetos con un método toString() válido es el resultado de llamar a object.toString() ( §8.12.8 ). Para las matrices, esto es lo mismo que llamar a array.join() ( §15.4.4.2 ). Unir una matriz vacía da como resultado una cadena vacía, por lo que el paso 7 del operador de adición devuelve la concatenación de dos cadenas vacías, que es la cadena vacía.

  2. [] + {}

    Similar a [] + [] , ambos operandos se convierten primero a primitivos. Para "Objetos de objeto" (§15.2), este es nuevamente el resultado de llamar a object.toString() , que para objetos no nulos, no indefinidos es "[object Object]" ( §15.2.4.2 ).

  3. {} + []

    El {} aquí no se analiza como un objeto, sino como un bloque vacío ( §12.1 , al menos siempre y cuando no esté forzando que esa declaración sea una expresión, pero más sobre esto más adelante). El valor de retorno de los bloques vacíos está vacío, por lo que el resultado de esa declaración es el mismo que +[] . El operador unario + ( §11.4.6 ) devuelve ToNumber(ToPrimitive(operand)) . Como ya sabemos, ToPrimitive([]) es la cadena vacía, y de acuerdo con §9.3.1 , ToNumber("") es 0.

  4. {} + {}

    Al igual que en el caso anterior, el primer {} se analiza como un bloque con valor de retorno vacío. De nuevo, +{} es el mismo que ToNumber(ToPrimitive({})) , y ToPrimitive({}) es "[object Object]" (ver [] + {} ). Entonces, para obtener el resultado de +{} , debemos aplicar ToNumber en la cadena "[object Object]" . Al seguir los pasos de §9.3.1 , obtenemos NaN como resultado:

    Si la gramática no puede interpretar el String como una expansión de StringNumericLiteral , entonces el resultado de ToNumber es NaN .

  5. Array(16).join("wat" - 1)

    Según §15.4.1.1 y §15.4.2.2 , Array(16) crea una nueva matriz con longitud 16. Para obtener el valor del argumento para unir, §11.6.2 , pasos # 5 y # 6 muestran que tenemos que convertir Ambos operandos a un número utilizando ToNumber . ToNumber(1) es simplemente 1 ( ToNumber ), mientras que ToNumber("wat") nuevamente es NaN según §9.3.1 . Siguiendo el paso 7 de §11.6.2 , §11.6.3 dicta que

    Si cualquiera de los operandos es NaN , el resultado es NaN .

    Así que el argumento de Array(16).join es NaN . Siguiendo §15.4.4.5 ( Array.prototype.join ), tenemos que llamar a ToString en el argumento, que es "NaN" ( §9.8.1 ):

    Si m es NaN , devuelva la cadena "NaN" .

    Siguiendo el paso 10 de §15.4.4.5 , obtenemos 15 repeticiones de la concatenación de "NaN" y la cadena vacía, que es igual al resultado que estás viendo. Cuando se usa "wat" + 1 lugar de "wat" - 1 como argumento, el operador de suma convierte 1 en una cadena en lugar de convertir "wat" en un número, por lo que llama a Array(16).join("wat1") .

En cuanto a por qué estás viendo resultados diferentes para el caso {} + [] : cuando lo usas como un argumento de función, estás forzando que la declaración sea una Expresión de Expresión , lo que hace imposible analizar {} como un bloque vacío, por lo que en cambio, se analiza como un objeto vacío literal.


Esto es más un comentario que una respuesta, pero por alguna razón no puedo comentar sobre tu pregunta. Quería corregir tu código JSFiddle. Sin embargo, publiqué esto en Hacker News y alguien sugirió que lo volviera a publicar aquí.

El problema en el código de JSFiddle es que ({}) (abrir llaves entre paréntesis) no es lo mismo que {} (abrir llaves como el inicio de una línea de código). Así que cuando escribes out({} + []) estás forzando que {} sea ​​algo que no es cuando escribes {} + [] . Esto es parte de la ''wat''-ness general de Javascript.

La idea básica era que JavaScript simple quería permitir estas dos formas:

if (u) v; if (x) { y; z; }

Para ello, se hicieron dos interpretaciones de la abrazadera de apertura: 1. no es obligatorio y 2. puede aparecer en cualquier lugar .

Este fue un movimiento equivocado. El código real no tiene una llave de apertura que aparece en el medio de la nada, y el código real también tiende a ser más frágil cuando usa la primera forma en lugar de la segunda. (Aproximadamente una vez cada dos meses en mi último trabajo, me llamaban al escritorio de un compañero de trabajo cuando sus modificaciones a mi código no funcionaban, y el problema era que habían agregado una línea al "si" sin agregar Finalmente, adopté el hábito de que las llaves siempre son necesarias, incluso cuando solo estás escribiendo una línea.)

Afortunadamente, en muchos casos, eval () replicará el flujo completo de JavaScript. El código de JSFiddle debería leer:

function out(code) { function format(x) { return typeof x === "string" ? JSON.stringify(x) : x; } document.writeln(''&gt;&gt;&gt; '' + code); document.writeln(format(eval(code))); } document.writeln("<pre>"); out(''[] + []''); out(''[] + {}''); out(''{} + []''); out(''{} + {}''); out(''Array(16).join("wat" + 1)''); out(''Array(16).join("wat - 1")''); out(''Array(16).join("wat" - 1) + " Batman!"''); document.writeln("</pre>");

[También es la primera vez que escribo document.writeln en muchos, muchos años, y me siento un poco sucio escribiendo cualquier cosa relacionada con document.writeln () y eval ().]


Para reforzar lo que se ha compartido anteriormente.

La causa subyacente de este comportamiento se debe en parte a la naturaleza débil de JavaScript. Por ejemplo, la expresión 1 + "2" es ambigua ya que hay dos interpretaciones posibles basadas en los tipos de operandos (int, string) y (int int):

  • El usuario tiene la intención de concatenar dos cadenas, resultado: "12"
  • Usuario pretende sumar dos números, resultado: 3

Así, con diferentes tipos de entrada, las posibilidades de salida aumentan.

El algoritmo de suma.

  1. Coaccionar operandos a valores primitivos.

Las primitivas de JavaScript son cadena, número, nulo, indefinido y booleano (el símbolo estará disponible próximamente en ES6). Cualquier otro valor es un objeto (por ejemplo, matrices, funciones y objetos). El proceso de coerción para convertir objetos en valores primitivos se describe así:

  • Si se devuelve un valor primitivo cuando se invoca object.valueOf (), entonces devuelva este valor, de lo contrario continúe

  • Si se devuelve un valor primitivo cuando se invoca object.toString (), entonces devuelva este valor, de lo contrario continúe

  • Lanzar un error de tipo

Nota: Para los valores de fecha, el orden es invocar a String antes de valueOf.

  1. Si cualquier valor de operando es una cadena, entonces haga una concatenación de cadena

  2. De lo contrario, convierta ambos operandos a su valor numérico y luego agregue estos valores

Conocer los diversos valores de coerción de tipos en JavaScript ayuda a aclarar los resultados confusos. Vea la tabla de coerción a continuación

+-----------------+-------------------+---------------+ | Primitive Value | String value | Numeric value | +-----------------+-------------------+---------------+ | null | “null” | 0 | | undefined | “undefined” | NaN | | true | “true” | 1 | | false | “false” | 0 | | 123 | “123” | 123 | | [] | “” | 0 | | {} | “[object Object]” | NaN | +-----------------+-------------------+---------------+

También es bueno saber que el operador + de JavaScript es asociativo a la izquierda, ya que esto determina cuál será el resultado en los casos que involucran más de una operación +.

Aprovechar el Así 1 + "2" dará "12" porque cualquier adición que involucre una cadena siempre será por defecto la concatenación de cadenas.

Puedes leer más ejemplos en esta publicación de blog (descargo de responsabilidad que lo escribí).


Podemos referirnos a la especificación y eso es excelente y más preciso, pero la mayoría de los casos también se pueden explicar de una manera más comprensible con las siguientes afirmaciones:

  • + operadores + y - trabajan solo con valores primitivos. Más específicamente, + (adición) funciona con cadenas o números, y + (unario) y - (resta y unario) solo funciona con números.
  • Todas las funciones u operadores nativos que esperan un valor primitivo como argumento, primero convertirán ese argumento al tipo primitivo deseado. Se realiza con valueOf o toString , que están disponibles en cualquier objeto. Esa es la razón por la que tales funciones u operadores no generan errores cuando se invocan en objetos.

Entonces podemos decir que:

  • [] + [] es igual que String([]) + String([]) que es igual que '''' + '''' . Mencioné anteriormente que + (adición) también es válido para números, pero no hay una representación de número válida de una matriz en JavaScript, así que en su lugar se usa la adición de cadenas.
  • [] + {} es igual que String([]) + String({}) que es igual que '''' + ''[object Object]''
  • {} + [] . Esta merece más explicación (ver respuesta de Ventero). En ese caso, las llaves no se tratan como un objeto sino como un bloque vacío, por lo que resulta igual a +[] . Unary + solo funciona con números, por lo que la implementación intenta obtener un número de [] . En primer lugar, intenta valueOf que en el caso de matrices devuelve el mismo objeto, y luego intenta el último recurso: la conversión de un resultado de toString a un número. Podemos escribirlo como +Number(String([])) que es igual a +Number('''') que es igual a +0 .
  • Array(16).join("wat" - 1) resta - funciona solo con números, por lo que es lo mismo que: Array(16).join(Number("wat") - 1) , como "wat" no puede ser convertido a un número válido. Recibimos NaN y cualquier operación aritmética en los resultados de NaN con NaN , por lo que tenemos: Array(16).join(NaN) .

Yo segundo la solución de @Ventero. Si lo desea, puede entrar en más detalles sobre cómo + convierte sus operandos.

Primer paso (§9.1): convierta ambos operandos a primitivos (los valores primitivos son undefined , null , booleanos, números, cadenas; todos los demás valores son objetos, incluidas matrices y funciones). Si un operando ya es primitivo, ya está hecho. Si no, es un objeto obj y se realizan los siguientes pasos:

  1. Llame a obj.valueOf() . Si devuelve un primitivo, ya está hecho. Las instancias directas de Object y matrices se devuelven, por lo que aún no ha terminado.
  2. Llame a obj.toString() . Si devuelve un primitivo, ya está hecho. {} y [] ambos devuelven una cadena, así que has terminado.
  3. De lo contrario, lanza un TypeError .

Para las fechas, los pasos 1 y 2 se intercambian. Puede observar el comportamiento de conversión de la siguiente manera:

var obj = { valueOf: function () { console.log("valueOf"); return {}; // not a primitive }, toString: function () { console.log("toString"); return {}; // not a primitive } }

Interacción ( Number() primero se convierte en primitivo y luego en número):

> Number(obj) valueOf toString TypeError: Cannot convert object to primitive value

Segundo paso (§11.6.1): Si uno de los operandos es una cadena, el otro operando también se convierte en cadena y el resultado se produce al concatenar dos cadenas. De lo contrario, ambos operandos se convierten en números y el resultado se produce al agregarlos.

Explicación más detallada del proceso de conversión: “ 2ality.com/2012/01/object-plus-object.html