En primer lugar, quiero aclarar, sé que with
está en desuso , y usarlo generalmente es una mala práctica .
Sin embargo, mi pregunta es sobre un caso especial: usar un Proxy
objeto especial como parámetro de with
.
Antecedentes
Estoy trabajando en un proyecto, donde tengo que limitar el acceso de un código al alcance global.
Un enfoque podría ser usar un bucle con eval
, que crea variables constantes con el valor de undefined
para cada propiedad del objeto global, pero eso parece aún peor que usar with
, y no puede limitar el acceso a las variables creadas con let
y const
.
La idea
La idea es utilizar a Proxy
como argumento de with
, cuyo ...
has
trap siempre regresatrue
, por lo tanto, no permite que ninguna búsqueda o tarea vaya más allá de lawith
declaraciónget
trap funciona normalmente, excepto que arrojanReferenceError
s cuando intentan acceder a una variable no existente (es decir, propiedad)set
la trampa funciona normalmente (o puede contener alguna lógica personalizada)target
el objeto no tiene[[Prototype]]
(es decir, se creó conObject.create(null)
)target
El objeto tiene una@@unscopables
propiedad, con el valor de un objeto vacío, para permitir el alcance de cada propiedad
Entonces, algo como este código:
const scope = Object.create(null)
Object.assign(scope, {
undefined,
console,
String,
Number,
Boolean,
Array,
Object,
/* etc. */
[Symbol.unscopables]: Object.create(null)
})
const scopeProxy = new Proxy(scope, {
get: (obj, prop) => {
if (prop in obj)
return obj[prop]
else
throw new ReferenceError(`${prop} is not defined`)
},
set: Reflect.set,
has: () => true
})
with(scopeProxy) {
//Sandboxed code
foo = Number('42')
console.log(foo) //42
try{
console.log(scopeProxy) //Inaccessible
}catch(e){
console.error(e) //ReferenceError: scopeProxy is not defined
}
}
Evitar contras
Hay varias contras enumeradas en la página de MDN sobre la with
declaración , pero este uso elimina todas.
1. Rendimiento
El problema:
Buscar identificadores que no sean miembros del
with
objeto de parámetro de la declaración es menos eficaz.Evitación:
Ninguna búsqueda puede ir más allá del objeto de parámetro.
2. Ambigüedad
El problema:
Es difícil decidir qué identificador se busca de aquellos con el mismo nombre.
Evitación:
Todas las búsquedas y asignaciones recuperan o modifican la propiedad del objeto de parámetro.
3. compatibilidad hacia adelante
El problema:
Las propiedades de los objetos de parámetros o sus prototipos pueden cambiar en el futuro.
Evitación:
El objeto de parámetro está inicialmente vacío y no tiene prototipo, por lo tanto, ninguna propiedad puede cambiar.
Pregunta
El código anterior funciona perfectamente, y los contras enumerados en MDN no se aplican a esto.
Entonces, mi pregunta es:
¿Sigue siendo una mala práctica usar la with
declaración, y si es así, cuáles son las desventajas de usarla en este caso?
with
esta manera es malo o no.with
un proxy todavía es bastante lento. Intentaría buscar una solución diferente para el problema subyacente, pero aparte de eso, solo lo está utilizandowith
como una herramienta que parece hacer lo que necesita.Respuestas:
Suena como el viejo tema de alcance léxico vs dinámico . En general, el alcance léxico es más seguro, pero en algunas situaciones el alcance dinámico tiene sentido, ya que simplifica mucho algunas soluciones. Diría que su ejemplo es uno de los casos, donde puede ser útil.
fuente