10

Para escribir una respuesta a ¿Cómo funciona el condicional if (!+[]+!+[] == 2) en JavaScript? me aventuré a utilizar https://www.ecma-international.org/ecma-262/7.0/index.html para las referencias.

En ToPrimitive se explica el procedimiento para convertir una valor en un valor primitivo pero no he logrado asimilarlo para el caso de [].

Sé que [] es un objeto y que es equivalente a new Array() También sé que un array es un objeto exótico, así que uno o más de sus métodos internos esenciales no tiene comportamiento predeterminado.


Notas:

  1. Comentario de Paul Vargas (chat)
  2. Revisar Array objects (sección de ECMAScript 2016)


Otras pregunta relacionadas:
Rubén
  • 10,857
  • 6
  • 35
  • 79

2 Answers2

5

Respuesta corta

El valor primitivo de [] es '' (cadena de texto vacía).

Explicación

Finalmente me decidí a googlear y encontré esta respuesta a Why does ++[[]][+[]]+[+[]] return the string “10”?1, la cual es similar a mi respuesta a ¿Cómo funciona el condicional if (!+[]+!+[] == 2) en JavaScript? en cuando a que hace referencia a una especificación ECMASCript sólo que aquella no especifica a cual versión se refieren las citas, sin embargo, me ha sido útil para llenar el "hueco" que derivó en esta pregunta.

Mas abajo incluyo un par de extractos los cuales se pueden resumir como

document.write([].join() === '') // Resultado true

Extractos de la ECMAScript 2016 (versión 7)


12.2.5Array Initializer

NOTE An ArrayLiteral is an expression describing the initialization of an Array > object, using a list, of zero or more expressions each of which represents an array element, enclosed in square brackets. The elements need not be literals; they are evaluated each time the array initializer is evaluated.

Array elements may be elided at the beginning, middle or end of the element list. Whenever a comma in the element list is not preceded by an AssignmentExpression (i.e., a comma at the beginning or after another comma), the missing array element contributes to the length of the Array and increases the index of subsequent elements. Elided array elements are not defined. If an element is elided at the end of an array, that element does not contribute to the length of the Array.


7.1.1 ToPrimitive ( input [ , PreferredType ] )

The abstract operation ToPrimitive takes an input argument and an optional argument PreferredType. The abstract operation ToPrimitive converts its input argument to a non-Object type. If an object is capable of converting to more than one primitive type, it may use the optional hint PreferredType to favour that type. Conversion occurs according to Table 9:

Table 9: ToPrimitive Conversions

Input Type  Result
Undefined   Return input.
Null        Return input.
Boolean     Return input.
Number      Return input.
String      Return input.
Symbol      Return input.
Object      Perform the steps following this table.

When Type(input) is Object, the following steps are taken:

  1. If PreferredType was not passed, let hint be "default".
  2. Else if PreferredType is hint String, let hint be "string".
  3. Else PreferredType is hint Number, let hint be "number".
  4. Let exoticToPrim be ? GetMethod(input, @@toPrimitive).
  5. If exoticToPrim is not undefined, then
    1. Let result be ? Call(exoticToPrim, input, « hint »).
    2. If Type(result) is not Object, return result.
    3. Throw a TypeError exception.
  6. If hint is "default", let hint be "number".
  7. Return ? OrdinaryToPrimitive(input, hint).

When the abstract operation OrdinaryToPrimitive is called with arguments O and hint, the following steps are taken:

  1. Assert: Type(O) is Object.
  2. Assert: Type(hint) is String and its value is either "string" or "number".
  3. If hint is "string", then
    1. Let methodNames be « "toString", "valueOf" ».
  4. Else,
    1. Let methodNames be « "valueOf", "toString" ».
  5. For each name in methodNames in List order, do
    1. Let method be ? Get(O, name).
    2. If IsCallable(method) is true, then
    3. Let result be ? Call(method, O).
    4. If Type(result) is not Object, return result.
  6. Throw a TypeError exception.

NOTE

When ToPrimitive is called with no hint, then it generally behaves as if the hint were Number. However, objects may over-ride this behaviour by defining a @@toPrimitive method. Of the objects defined in this specification only Date objects (see 20.3.4.45) and Symbol objects (see 19.4.3.4) over-ride the default ToPrimitive behaviour. Date objects treat no hint as if the hint were String.

En el caso de un objeto de tipo Array, el método para determinar el valor primitivo es join() de acuerdo a lo siguiente:


22.1.3.28 Array.prototype.toString ( )

When the toString method is called, the following steps are taken:

  1. Let array be ? ToObject(this value).
  2. Let func be ? Get(array, "join").
  3. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString%.
  4. Return ? Call(func, array).

NOTE

The toString function is intentionally generic; it does not require that its this value be an Array object. Therefore it can be transferred to other kinds of objects for use as a method.


Rubén
  • 10,857
  • 6
  • 35
  • 79
2

Teniendo:

+[]

De acuerdo con §11.4.6, +[] se evalúa como sigue:

ToNumber(GetValue([]))

De acuerdo con §8.7.1, GetValue devuelve el mismo objeto ya que no es Reference.

ToNumber([])

De acuerdo con §9.3 y typeof [] === "object", entonces se aplica al argumento:

ToNumber(ToPrimitive([], hint Number))

De acuerdo con §9.1 y typeof [] === "object", entonces se llama al método interno [[DefaultValue]]

De acuerdo con §9.3.1, el valor matemático de una cadena vacía es 0.

Paul Vargas
  • 181
  • 1
  • 20
  • 39