javascript - the - ¿Por qué `“ foo ”.bar=42;` lanza `TypeError` en modo estricto en ES6?
use the function form of use strict (2)
De acuerdo con la especificación ES5.1, el programa "use strict;" "foo".bar = 42;
"use strict;" "foo".bar = 42;
hace que se cree un objeto String
, se lo asigna a una propiedad y luego lo tira, lo que no produce efectos observables, incluidas las excepciones. (La ausencia de efecto puede confirmarse al intentarlo en una implementación JS compatible con ES5 como la de Opera 12.)
En las implementaciones modernas de JS, lanza un TypeError
lugar, pruébelo:
"use strict"; "foo".bar = 42;
Estoy bastante seguro de que el nuevo comportamiento es obligatorio por la especificación ES6, pero a pesar de leer las secciones relevantes varias veces, no puedo ver dónde se especifica que se TypeError
. De hecho, las partes clave parecen estar sin cambios:
6.2.3.2 PutValue ( V , W ) #
- ReturnIfAbrupt ( V ).
- ReturnIfAbrupt ( W ).
- Si el Tipo ( V ) no es Referencia, lanza una excepción ReferenceError .
- Que la base sea GetBase ( V ).
- Si IsUnresolvableReference ( V ) es verdadero, entonces
- ...
- De lo contrario, si IsPropertyReference ( V ) es verdadero, entonces
- a. Si HasPrimitiveBase ( V ) es verdadero, entonces
- yo. Afirmar: En este caso, la base nunca será nula o indefinida.
- ii. Establecer la base a ToObject ( base ).
- segundo. Que se logre ser? base . [[Set]] (GetReferencedName ( V ), W , GetThisValue ( V )).
- do. ReturnIfAbrupt (lo logró ).
- re. Si tiene éxito es falso e IsStrictReference ( V ) es verdadero, lance una excepción TypeError .
- mi. Regreso.
- ...
¿Dónde obliga la especificación (ES6 o posterior) a lanzar TypeError
?
La respuesta de @georg parece ser la interpretación correcta de ES6 +, pero parece que el comportamiento tampoco es nuevo. Desde ES5.1 PutValue :
Si no es IsPropertyReference (V), entonces
a. Si HasPrimitiveBase (V) es falso, entonces deje que sea el método interno de [[Put]] base, de lo contrario , deje que sea el método interno especial [[Put]] definido a continuación .
segundo. Llame al método interno puesto usando base como su valor, y pasando GetReferencedName (V) para el nombre de la propiedad, W para el valor, e IsStrictReference (V) para el indicador Throw .
y en la referencia [[Put]]:
Si no, esta es una solicitud para crear una propiedad propia en el objeto transitorio O
a. Si Throw es verdadero, lanza una excepción TypeError.
Parece que probablemente estoy malinterpretando algo ... pero, ¿a qué otra cosa podría estar refiriéndose "esta es una solicitud para crear una propiedad propia en el objeto transitorio O"?
Supongo que está aquí:
http://www.ecma-international.org/ecma-262/7.0/#sec-ordinaryset
9.1.9.1. OrdinarySet (O, P, V, Receptor)
[...]
4.b. Si el Tipo (Receptor) no es Objeto, devuelva falso.
(Anteriormente llamado [[Set]], en ES6 §9.1.9 .)
Aunque PutValue
promueve la base
a un objeto, no hace lo mismo con el receptor: GetThisValue(V)
aún se llama en la V
original (con una base primitiva). Por lo tanto, GetThisValue
devuelve una primitiva, OrdinarySet.4b
falla al asignar un ownDesc
recién creado y devuelve false
, y esto a su vez hace que PutValue.6d
lance un TypeError, siempre que la referencia sea estricta.
La parte correspondiente de V8 parece seguir la misma lógica:
Maybe<bool> Object::AddDataProperty(....
if (!it->GetReceiver()->IsJSReceiver()) {
return CannotCreateProperty(...
https://github.com/v8/v8/blob/3b39fc4dcdb6593013c497fc9e28a1d73dbcba03/src/objects.cc#L5140