Antes de tudo, quero esclarecer, sei que isso with
foi preterido e usá-lo geralmente é uma prática ruim .
No entanto, minha pergunta é sobre um caso especial: usar um Proxy
objeto especial como parâmetro de with
.
fundo
Estou trabalhando em um projeto, no qual tenho que limitar o acesso de um pedaço de código ao escopo global.
Uma abordagem pode ser usar um loop com eval
, que cria variáveis constantes com o valor de undefined
para cada propriedade do objeto global, mas isso parece ainda pior do que usar with
e não pode limitar o acesso a variáveis criadas com let
e const
.
A ideia
A idéia é usar a Proxy
como argumento de with
, cuja ...
has
A armadilha sempre retornatrue
, portanto, não permite que nenhuma pesquisa ou atribuição vá além dawith
instruçãoget
A armadilha opera normalmente, exceto que eles lançamReferenceError
s ao tentar acessar uma variável inexistente (ou seja, propriedade)set
a armadilha opera normalmente (ou talvez contenha alguma lógica personalizada)target
O objeto não possui[[Prototype]]
(ou seja, foi criado comObject.create(null)
)target
O objeto tem uma@@unscopables
propriedade, com o valor de um objeto vazio, para permitir o escopo de cada propriedade
Então, 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
}
}
Evitando contras
Existem vários contras listados na página do MDN sobre a with
declaração , mas esse uso se livra de cada uma.
1. Desempenho
O problema:
A pesquisa de identificadores que não são membros do
with
objeto de parâmetro da instrução tem menos desempenho.Prevenção:
Nenhuma pesquisa pode ir além do objeto de parâmetro.
2. Ambiguidade
O problema:
É difícil decidir qual identificador é procurado por pessoas com o mesmo nome.
Prevenção:
Todas as pesquisas e atribuições recuperam ou modificam a propriedade do objeto de parâmetro.
3. Compatibilidade futura
O problema:
As propriedades dos objetos de parâmetro ou seus protótipos podem mudar no futuro.
Prevenção:
O objeto de parâmetro está inicialmente vazio e não possui protótipo; portanto, nenhuma propriedade pode ser alterada.
Questão
O código acima funciona perfeitamente e os contras listados no MDN não se aplicam a isso.
Então, minha pergunta é:
Ainda é uma má prática usar a with
declaração e, em caso afirmativo, quais são as desvantagens de usá-la nesse caso?
with
dessa maneira é ruim ou não.with
um proxy ainda é bastante lento. Eu tentaria procurar uma solução diferente para o problema subjacente, mas fora isso, você está apenas usandowith
como uma ferramenta que parece fazer o que você precisa.Respostas:
Parece o bom e velho tópico lexical vs dynamic scope . Em geral, o escopo lexical é mais seguro, mas em algumas situações o escopo dinâmico faz sentido, porque simplifica muito algumas soluções. Eu diria que seu exemplo é um dos casos em que pode ser útil.
fonte