Os comentários de Alan Storm em resposta à minha resposta sobre a with
declaração me fizeram pensar. Eu raramente encontrei um motivo para usar esse recurso de idioma específico e nunca pensei muito em como ele poderia causar problemas. Agora, estou curioso para saber como posso fazer uso efetivo with
, evitando as armadilhas.
Onde você achou a with
declaração útil?
with
para que não exista mais tal coisa.Respostas:
Outro uso me ocorreu hoje, então procurei na web com entusiasmo e encontrei uma menção existente: Definindo Variáveis no Escopo do Bloco .
fundo
O JavaScript, apesar de sua semelhança superficial com C e C ++, não define variáveis para o bloco em que são definidas:
Declarar um fechamento em um loop é uma tarefa comum em que isso pode levar a erros:
Como o loop for não introduz um novo escopo, o mesmo
num
- com um valor de2
- será compartilhado pelas três funções.Um novo escopo:
let
ewith
Com a introdução da
let
declaração no ES6 , torna-se fácil introduzir um novo escopo quando necessário para evitar esses problemas:Ou até:
Até que o ES6 esteja universalmente disponível, esse uso permanece limitado aos navegadores e desenvolvedores mais novos que desejam usar transpilers. No entanto, podemos simular facilmente esse comportamento usando
with
:O loop agora funciona como pretendido, criando três variáveis separadas com valores de 0 a 2. Observe que as variáveis declaradas no bloco não têm escopo definido para ele, diferentemente do comportamento dos blocos em C ++ (em C, as variáveis devem ser declaradas no início de um bloco, de modo que é semelhante). Esse comportamento é realmente muito semelhante a uma
let
sintaxe de bloco introduzida em versões anteriores dos navegadores Mozilla, mas não amplamente adotada em outros lugares.fonte
for (var i = 0; i < 3; ++i) { setTimeout ((function () { var num = i; return function () { alert (num); }; }) (), 10);}
var toString = function () { return "Hello"; }; with ({"test":1}) { console.log(toString()); };
,. No escopo da instrução with , toString () é uma propriedade herdada de Object , portanto a função definida explicitamente não é chamada. Ainda uma grande resposta, embora :-)Eu tenho usado o com declaração como uma forma simples de importação com escopo. Digamos que você tenha algum tipo de construtor de marcações. Em vez de escrever:
Você poderia escrever:
Para este caso de uso, não estou realizando nenhuma atribuição, portanto não tenho o problema de ambiguidade associado a isso.
fonte
context.bezierCurveTo
cem vezes seguidas, poderá dizervar bc2 = context.bezierCurveTo;
e depois irbc2(x,x,etc);
sempre que quiser chamá-lo. Isso é muito rápido e menos detalhado, enquantowith
é super lento.Como meus comentários anteriores indicaram, não acho que você possa usar
with
com segurança, por mais tentador que seja em qualquer situação. Como o problema não é abordado diretamente aqui, repetirei. Considere o seguinte códigoSem investigar cuidadosamente essas chamadas de função, não há como saber qual será o estado do seu programa após a execução desse código. Se
user.name
já foi definido, será agoraBob
. Se não foi definido, o globalname
será inicializado ou alterado paraBob
e ouser
objeto permanecerá sem umaname
propriedade.Erros acontecem. Se você usar com você, eventualmente fará isso e aumentará as chances de seu programa falhar. Pior, você pode encontrar código de trabalho que define um global no bloco com, deliberadamente ou através do autor que não conhece essa peculiaridade da construção. É como encontrar falhas em um switch, você não tem idéia se o autor pretendeu isso e não há como saber se "consertar" o código introduzirá uma regressão.
As linguagens de programação modernas estão repletas de recursos. Alguns recursos, após anos de uso, são considerados ruins e devem ser evitados. Javascript
with
é um deles.fonte
Na verdade, achei a
with
declaração incrivelmente útil recentemente. Essa técnica realmente nunca me ocorreu até que eu iniciei meu projeto atual - um console de linha de comando escrito em JavaScript. Eu estava tentando emular as APIs do console Firebug / WebKit, nas quais comandos especiais podem ser inseridos no console, mas eles não substituem nenhuma variável no escopo global. Pensei nisso ao tentar superar um problema mencionado nos comentários à excelente resposta de Shog9 .Para alcançar esse efeito, usei duas instruções com "camada" de um escopo por trás do escopo global:
O melhor dessa técnica é que, além das desvantagens de desempenho, ela não sofre os medos usuais da
with
declaração, porque estamos avaliando no escopo global de qualquer maneira - não há perigo de variáveis fora do nosso pseudo-escopo serem modificado.Fiquei inspirado a postar esta resposta quando, para minha surpresa, consegui encontrar a mesma técnica usada em outros lugares - o código-fonte do Chromium !
EDIT: Apenas verifiquei a fonte do Firebug, eles encadearam 4 com instruções juntas para ainda mais camadas. Louco!
fonte
Sim sim e sim. Existe um uso muito legítimo. Ver:
Basicamente, quaisquer outros ganchos DOM ou CSS são usos fantásticos com. Não é como se "CloneNode" fosse indefinido e retornasse ao escopo global, a menos que você se esforçasse e decidisse tornar isso possível.
A queixa de velocidade de Crockford é que um novo contexto é criado com. Os contextos são geralmente caros. Concordo. Mas se você acabou de criar uma div e não possui uma estrutura disponível para definir seu css e precisa configurar 15 ou mais propriedades CSS manualmente, criar um contexto provavelmente será mais barato que a criação de variáveis e 15 dereferences:
etc ...
fonte
with
. No entanto, neste caso em particular, você pode fazer o seguinte:element.style.cssText="background: black ; color: blue ; border: 1px solid green"
extend
método de qualquer jQuery ou Underscore.js:$.extend(element.style, {fontWeight: 'bold', fontSize: '1.5em', color: '#55d', marginLeft: '2px'})
..css()
método ...Você pode definir uma função auxiliar pequena para fornecer os benefícios
with
sem a ambiguidade:fonte
with_
ser uma versão dupla e enlameada(function(_){ _.a="foo"; })(object_here);
(a maneira padrão de simular blocos no estilo c / java). Use isso em vez disso.Dificilmente parece valer a pena, pois você pode fazer o seguinte:
fonte
with
.Eu nunca uso com, não vejo um motivo e não o recomendo.
O problema
with
é que ele impede inúmeras otimizações lexicais que uma implementação do ECMAScript pode executar. Dado o surgimento de mecanismos rápidos baseados em JIT, esse problema provavelmente se tornará ainda mais importante no futuro próximo.Pode parecer que
with
permite construções mais limpas (quando, digamos, introduzir um novo escopo em vez de um invólucro de função anônima comum ou substituir um apelido detalhado), mas realmente não vale a pena . Além de um desempenho reduzido, sempre há o risco de atribuir a uma propriedade de um objeto errado (quando a propriedade não é encontrada em um objeto no escopo injetado) e talvez introduzir erroneamente variáveis globais. IIRC, última questão que motivou Crockford a recomendar a evitarwith
.fonte
with(){}
construções como as fornecidas em outras respostas aqui, em navegadores modernos, eu adoraria ver eles!with(){}
: configurar um novo escopo comwith
um custo enorme em todos os navegadores que testei. Você deseja evitar isso em qualquer código chamado com muita frequência. Além disso, o Chrome exibiu um sucesso dramático para qualquer código executado dentro de umwith()
escopo. Curiosamente, o IE tinha as melhores características de desempenho para o código dentro dewith()
blocos: calcular o custo de instalação,with()
fornece os meios mais rápidos de acesso de membros nas VMs do IE6 e IE8 (embora essas VMs sejam as mais lentas no geral). Coisas boas, obrigado ...with()
é quase uma ordem de magnitude mais lenta no Chrome e duas vezes mais rápida no IE ...!Visual Basic.NET tem uma
With
declaração semelhante . Uma das maneiras mais comuns de uso é definir rapidamente várias propriedades. Ao invés de:, Eu consigo escrever:
Isso não é apenas uma questão de preguiça. Também contribui para um código muito mais legível. E, diferentemente do JavaScript, ele não sofre ambiguidade, pois você precisa prefixar tudo que é afetado pela instrução com um
.
(ponto). Portanto, os dois seguintes são claramente distintos:vs.
O primeiro é
someObject.Foo
; o último estáFoo
no escopo externosomeObject
.Acho que a falta de distinção do JavaScript o torna muito menos útil do que a variante do Visual Basic, pois o risco de ambiguidade é muito alto. Fora isso,
with
ainda é uma idéia poderosa que pode melhorar a legibilidade.fonte
Você pode usar
with
para introduzir o conteúdo de um objeto como variáveis locais em um bloco, como está sendo feito com esse pequeno mecanismo de modelo .fonte
Usar "com" pode tornar seu código mais seco.
Considere o seguinte código:
Você pode secá-lo da seguinte maneira:
Eu acho que depende se você tem preferência por legibilidade ou expressividade.
O primeiro exemplo é mais legível e provavelmente recomendado para a maioria dos códigos. Mas a maioria dos códigos é bem manso de qualquer maneira. O segundo é um pouco mais obscuro, mas usa a natureza expressiva da linguagem para reduzir o tamanho do código e as variáveis supérfluas.
Eu imagino que pessoas que gostam de Java ou C # escolheriam a primeira maneira (object.member) e aquelas que preferem Ruby ou Python escolheriam a segunda.
fonte
Eu acho que o uso óbvio é como um atalho. Se você está, por exemplo, inicializando um objeto, basta salvar digitando muito "ObjectName". Como os "com slots" do lisp, que permitem escrever
que é o mesmo que escrever
É mais óbvio por que esse é um atalho quando seu idioma permite "Objectname.foo", mas ainda assim.
fonte
with-slots
necessário especificar quais slots você está usando, ao passowith
que usará os slots que forem vinculados no tempo de execução.Tendo experiência com o Delphi, eu diria que usar com deve ser uma otimização de tamanho de último recurso, possivelmente realizada por algum tipo de algoritmo minimizador de javascript com acesso à análise de código estático para verificar sua segurança.
Os problemas de escopo em que você pode entrar com o uso liberal da declaração with podem ser uma dor real no a ** e eu não gostaria que alguém experimentasse uma sessão de depuração para descobrir o que ele está acontecendo no seu código , apenas para descobrir que ele capturou um membro do objeto ou a variável local incorreta, em vez da variável de escopo global ou externa que você pretendia.
O VB com declaração é melhor, na medida em que precisa dos pontos para desambiguar o escopo, mas o Delphi with é uma arma carregada com um gatilho, e parece-me que o javascript é semelhante o suficiente para garantir o mesmo aviso.
fonte
O uso com não é recomendado e é proibido no modo estrito do ECMAScript 5. A alternativa recomendada é atribuir o objeto cujas propriedades você deseja acessar a uma variável temporária.
Fonte: Mozilla.org
fonte
A instrução with pode ser usada para diminuir o tamanho do código ou para membros da classe privada, exemplo:
A declaração with é muito útil se você deseja modificar o escopo, o que é necessário para ter seu próprio escopo global que você pode manipular em tempo de execução. Você pode colocar constantes nele ou certas funções auxiliares frequentemente usadas como, por exemplo, "toUpper", "toLower" ou "isNumber", "clipNumber" também.
Sobre o mau desempenho que eu leio com frequência: o escopo de uma função não terá nenhum impacto no desempenho. De fato, no meu FF, uma função de escopo é executada mais rapidamente do que uma sem escopo:
Portanto, da maneira mencionada acima, a declaração with não tem efeito negativo no desempenho, mas é bom, pois diminui o tamanho do código, o que afeta o uso da memória em dispositivos móveis.
fonte
O uso com também torna seu código mais lento em muitas implementações, pois agora tudo é envolvido em um escopo extra de pesquisa. Não há motivo legítimo para usar com JavaScript.
fonte
var obj={a:0,b:0,c:0};var d=+new Date;with(obj){for(var i=0;i<1000000;++i){a+=1;b+=1;c+=1}}+new Date-d;
dá em média 2500, enquantovar obj={a:0,b:0,c:0};var d=+new Date;for(var i=0;i<1000000;++i){obj.a+=1;obj.b+=1;obj.c+=1}+new Date-d;
dá em média 750, tornando o uso mais de 3 vezes mais lento.with
código e 903 sem. Com essa pequena diferença, mesmo em um circuito fechado, eu faria uma seleção baseada na simplicidade da codificação e na facilidade de refatoração caso a caso, antes de me preocupar com o desempenho.Eu acho que a declaração with pode ser útil ao converter uma linguagem de modelo em JavaScript. Por exemplo, JST na base2 , mas já o vi com mais frequência.
Concordo que se pode programar isso sem a declaração with. Mas, por não causar problemas, é um uso legítimo.
fonte
É bom colocar um código que é executado em um ambiente relativamente complicado em um contêiner: eu o uso para criar uma ligação local para "window" e executar código destinado a um navegador da web.
fonte
Eu acho que o uso literal do objeto é interessante, como um substituto para usar um fechamento
ou a declaração with equivalente a um fechamento
Eu acho que o risco real é acidentalmente minipular variáveis que não fazem parte da instrução with, e é por isso que eu gosto do objeto literal que está sendo passado, você pode ver exatamente o que ele será no contexto adicionado no código.
fonte
Eu criei uma função de "mesclagem" que elimina parte dessa ambiguidade com a
with
instrução:Posso usá-lo de maneira semelhante
with
, mas sei que não afetará nenhum escopo que não pretendo que ele afete.Uso:
fonte
Para algumas partes curtas do código, eu gostaria de usar as funções trigonométricas como
sin
,cos
etc. , no modo grau, em vez de no modo radiante. Para esse propósito, eu uso umAngularDegree
objeto:Então eu posso usar as funções trigonométricas no modo grau sem mais ruído de linguagem em um
with
bloco:Isso significa: eu uso um objeto como uma coleção de funções, que eu habilito em uma região de código limitada para acesso direto. Eu acho isso útil.
fonte
with
declaração dessa maneira, apenas dificulta a leitura do código, porque você não sabe qual função é global e qual função é chamada no escopo de with object, portanto, se alguma função não estiver definida no escopo do objeto, em seguida, ele vai tentar acessá-lo no espaço globalz = Math.atan2( Math.sin(d * Math.PI / 180), Math.cos( pol.lat * Math.PI / 180) * Math.tan( pos.lat * Math.PI / 180 ) - Math.sin( pol.lat * Math.PI / 180 ) * Math.cos( d * Math.PI / 180) ) * 180 / Math.PI;
daria o mesmo resultado, mas é o horror.with
que podem te surpreender.Eu acho que a utilidade de
with
pode depender de quão bem o seu código é escrito. Por exemplo, se você estiver escrevendo um código que aparece assim:então você pode argumentar que
with
melhorará a legibilidade do código fazendo o seguinte:Por outro lado, pode-se argumentar que você está violando a Lei de Demeter , mas, novamente, talvez não. Eu discordo =).
Acima de tudo, saiba que Douglas Crockford recomenda não usar
with
. Exorto-vos a verificar o seu blog sobrewith
e suas alternativas aqui .fonte
Eu realmente não vejo como usar o with é mais legível do que digitar object.member. Não acho que seja menos legível, mas também não.
Como lassevk disse, eu definitivamente posso ver como o uso com seria mais suscetível a erros do que apenas a sintaxe "object.member" muito explícita.
fonte
Você pode ver a validação de um formulário em javascript no W3schools http://www.w3schools.com/js/js_form_validation.asp onde o formulário do objeto é "varrido" para encontrar uma entrada com o nome 'email'
Mas eu o modifiquei para obter de QUALQUER formulário todos os campos validados como não vazios, independentemente do nome ou quantidade de campo em um formulário. Bem, eu testei apenas campos de texto.
Mas o with () tornou as coisas mais simples. Aqui está o código:
fonte
O fork do CoffeeScript do Coco tem uma
with
palavra - chave, mas simplesmente definethis
(também gravável como@
no CoffeeScript / Coco) o objeto de destino dentro do bloco. Isso remove a ambiguidade e atinge a conformidade com o modo estrito do ES5:fonte
Aqui está um bom uso para
with
: adicionar novos elementos a um literal de objeto, com base nos valores armazenados nesse objeto. Aqui está um exemplo que eu acabei de usar hoje:Eu tinha um conjunto de peças possíveis (com aberturas voltadas para cima, baixo, esquerda ou direita) que poderiam ser usadas, e eu queria uma maneira rápida de adicionar uma lista de peças que sempre seriam colocadas e trancadas no início do jogo . Eu não queria continuar digitando
types.tbr
para cada tipo na lista, então apenas o useiwith
.fonte
Você pode usar with para evitar a necessidade de gerenciar explicitamente o arity ao usar o require.js:
Implementação de requirejs.declare:
fonte
Como Andy E apontou nos comentários da resposta de Shog9, esse comportamento potencialmente inesperado ocorre ao usar
with
com um objeto literal:Não que esse comportamento inesperado já não fosse uma marca registrada
with
.Se você realmente deseja usar essa técnica, use pelo menos um objeto com um protótipo nulo.
Mas isso só funcionará no ES5 +. Também não use
with
.fonte
Estou trabalhando em um projeto que permitirá aos usuários fazer upload de código para modificar o comportamento de partes do aplicativo. Nesse cenário, eu tenho usado uma
with
cláusula para impedir que o código modifique qualquer coisa fora do escopo com o qual eu quero que eles mexam. A parte (simplificada) do código que eu uso para fazer isso é:Esse código garante (um pouco) que o código definido pelo usuário não tenha acesso a objetos com escopo global, como
window
nem a nenhuma das minhas variáveis locais, por meio de um fechamento.Apenas como uma palavra para o sábio, ainda preciso executar verificações de código estático no código enviado pelo usuário para garantir que eles não estejam usando outras maneiras furtivas para acessar o escopo global. Por exemplo, o seguinte código definido pelo usuário obtém acesso direto a
window
:fonte
Minhas
se resume a
Você pode confiar em códigos de baixa qualidade? Não, vemos que foi tornado absolutamente ilegível. Este exemplo prova inegavelmente que não há necessidade de declaração com, se eu estiver assumindo a legibilidade corretamente;)
fonte