Existe alguma diferença entre declarar uma variável:
var a=0; //1
...deste jeito:
a=0; //2
...ou:
window.a=0; //3
no escopo global?
Existe alguma diferença entre declarar uma variável:
var a=0; //1
...deste jeito:
a=0; //2
...ou:
window.a=0; //3
no escopo global?
Respostas:
Sim, existem algumas diferenças, embora em termos práticos geralmente não sejam grandes.
Existe uma quarta maneira, e a partir do ES2015 (ES6) há mais duas. Eu adicionei a quarta maneira no final, mas inseri as formas do ES2015 após o 1 (você verá o porquê), então temos:
var a = 0; // 1
let a = 0; // 1.1 (new with ES2015)
const a = 0; // 1.2 (new with ES2015)
a = 0; // 2
window.a = 0; // 3
this.a = 0; // 4
# 1 var a = 0;
Isso cria uma variável global que também é propriedade do objeto global , ao qual acessamos como windownavegadores (ou via thisescopo global, em código não estrito). Ao contrário de outras propriedades, a propriedade não pode ser removida via delete.
Em termos de especificação, ele cria uma ligação de identificador no objeto Registro de Ambiente para o ambiente global . Isso o torna uma propriedade do objeto global porque é no objeto global que são mantidas as ligações de identificador para o registro de ambiente do objeto do ambiente global. É por isso que a propriedade não pode ser excluída: não é apenas uma propriedade simples, é uma ligação de identificador.
A ligação (variável) é definida antes da execução da primeira linha de código (consulte "Quando varacontece" abaixo).
Observe que no IE8 e versões anteriores, a propriedade criada em windownão é enumerável (não aparece nas for..ininstruções). No IE9, Chrome, Firefox e Opera, é enumerável.
# 1.1 let a = 0;
Isso cria uma variável global que não é uma propriedade do objeto global. Isso é algo novo a partir do ES2015.
Em termos de especificação, ele cria uma ligação de identificador no Declarative Environment Record para o ambiente global, em vez do objeto Environment Record. O ambiente global é o único a ter uma divisão Ambiente Record, um para todo o material antigo que se passa o objeto global (o objeto Ambiente Record) e outro para todo o material novo ( let, conste as funções criados por class) que não fazer vá no objeto global.
A ligação é criada antes da execução de qualquer código passo a passo em seu bloco anexo (neste caso, antes da execução de qualquer código global), mas não é acessível de maneira alguma até que a execução passo a passo chegue à letinstrução. Quando a execução atinge a letinstrução, a variável fica acessível. (Veja "Quando lete constacontece" abaixo.)
# 1.2 const a = 0;
Cria uma constante global, que não é uma propriedade do objeto global.
consté exatamente como letexceto que você deve fornecer um inicializador (a = valueparte), e você não pode alterar o valor da constante uma vez que é criado. Nos bastidores, é exatamente assim, letmas com uma bandeira na ligação do identificador dizendo que seu valor não pode ser alterado. O uso constfaz três coisas para você:
# 2 a = 0;
Isso cria uma propriedade no objeto global implicitamente . Como é uma propriedade normal, você pode excluí-la. Eu recomendo não fazer isso, pois pode não estar claro para quem ler seu código posteriormente. Se você usar o modo estrito do ES5, fazer isso (atribuir a uma variável inexistente) é um erro. É uma das várias razões para usar o modo estrito.
E, curiosamente, novamente no IE8 e versões anteriores, a propriedade criada não é enumerável (não aparece nas for..ininstruções). Isso é estranho, principalmente considerando o número 3 abaixo.
# 3 window.a = 0;
Isso cria uma propriedade explicitamente no objeto global, usando o windowglobal que se refere ao objeto global (em navegadores; alguns ambientes que não são de navegador têm uma variável global equivalente, como globalno NodeJS). Como é uma propriedade normal, você pode excluí-la.
Essa propriedade é enumerável, no IE8 e versões anteriores, e em todos os outros navegadores que tentei.
# 4 this.a = 0;
Exatamente como o nº 3, exceto que estamos referenciando o objeto global em thisvez do global window. Porém, isso não funcionará no modo estrito, porque no código global do modo estrito thisnão há uma referência ao objeto global (ele tem o valor undefined).
O que quero dizer com "excluindo" ou "removendo" a? Exatamente isso: Removendo a propriedade (inteiramente) por meio da deletepalavra-chave:
window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"
deleteremove completamente uma propriedade de um objeto. Você não pode fazer isso com as propriedades adicionadas windowindiretamente via var, o deleteé silenciosamente ignorado ou gera uma exceção (dependendo da implementação do JavaScript e se você está no modo estrito).
Aviso : IE8 novamente (e presumivelmente mais cedo, e IE9-IE11 no modo "compatibilidade" quebrado): não permitirá que você exclua propriedades do windowobjeto, mesmo quando lhe for permitido. Pior, isso gera uma exceção quando você tenta ( tente esta experiência no IE8 e em outros navegadores). Portanto, ao excluir do windowobjeto, você deve estar na defensiva:
try {
delete window.prop;
}
catch (e) {
window.prop = undefined;
}
Isso tenta excluir a propriedade e, se uma exceção for lançada, ela fará a próxima melhor coisa e definirá a propriedade undefined.
Isso se aplica apenas ao windowobjeto e apenas (tanto quanto eu sei) ao IE8 e versões anteriores (ou IE9-IE11 no modo "compatibilidade" quebrado). Outros navegadores estão bem com a exclusão de windowpropriedades, sujeitas às regras acima.
varaconteceAs variáveis definidas por meio da varinstrução são criadas antes da execução de qualquer código passo a passo no contexto de execução e, portanto, a propriedade existe bem antes da varinstrução.
Isso pode ser confuso, então vamos dar uma olhada:
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "undefined"
display("bar in window? " + ('bar' in window)); // displays "false"
display("window.bar = " + window.bar); // displays "undefined"
var foo = "f";
bar = "b";
display("foo in window? " + ('foo' in window)); // displays "true"
display("window.foo = " + window.foo); // displays "f"
display("bar in window? " + ('bar' in window)); // displays "true"
display("window.bar = " + window.bar); // displays "b"
Exemplo ao vivo:
Como você pode ver, o símbolo fooé definido antes da primeira linha, mas o símbolo barnão é. Onde está a var foo = "f";declaração, há realmente duas coisas: definir o símbolo, o que acontece antes da execução da primeira linha de código; e fazendo uma atribuição a esse símbolo, o que acontece onde a linha está no fluxo passo a passo. Isso é conhecido como " variçamento" porque a var foopeça é movida ("içada") para a parte superior do escopo, mas a foo = "f"peça é deixada em seu local original. (Veja Pobre mal entendidovar no meu pequeno blog anêmico.)
lete constacontecerlete constsão diferentes de varduas maneiras. A maneira que é relevante para a pergunta é que, embora a ligação que eles definem seja criada antes da execução de qualquer código passo a passo, ela não estará acessível até que a instrução letou constseja alcançada.
Então, enquanto isso é executado:
display(a); // undefined
var a = 0;
display(a); // 0
Isso gera um erro:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
As outras duas maneiras que diferem lete que não são realmente relevantes para a questão são:constvar
varsempre se aplica a todo o contexto de execução (em todo código global, ou durante todo código de função na função de onde ele aparece), mas lete constse aplicam apenas dentro do bloco onde eles aparecem. Ou seja, vartem a função (ou global) escopo, mas lete consttem escopo de bloco.
recorrente var a no mesmo contexto é inofensivo, mas se você tiver let a(ou const a), ter outro let aou a const aou a var aé um erro de sintaxe.
Aqui está um exemplo demonstrando que let e constentra em vigor imediatamente no bloco antes que qualquer código desse bloco seja executado, mas não está acessível até a instrução letou const:
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
Observe que o segundo console.logfalha, em vez de acessar o ade fora do bloco.
window)O windowobjeto fica muito, muito cheio de propriedades. Sempre que possível, é altamente recomendável não adicionar à bagunça. Em vez disso, embrulhe seus símbolos em um pequeno pacote e exporte no máximo um símbolo para o windowobjeto. (Frequentemente não exporto nenhum símbolo para o windowobjeto.) Você pode usar uma função para conter todo o seu código, a fim de conter seus símbolos, e essa função pode ser anônima, se você quiser:
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
Nesse exemplo, definimos uma função e a executamos imediatamente (a ()no final).
Uma função usada dessa maneira é freqüentemente chamada de função de escopo . As funções definidas na função de escopo podem acessar variáveis definidas na função de escopo porque são fechamentos sobre esses dados (consulte: Encerramentos não são complicados no meu pequeno blog anêmico).
window['a']=0para deixar claro que estou usando a janela como um mapa? é windowespecial de tal forma que alguns navegadores não permitem isso e me forçam a usar window.a?
window.a = 0;só funciona em ambientes de navegador e apenas por convenção. Binding o objeto global para uma variável chamada windownão está no ES Spec e assim não vai funcionar, por exemplo, V8 ou Node.js, enquanto this.a = 0;(quando invocada no contexto de execução global) irá funcionar em qualquer ambiente, desde a especificação não especificar que deve haver um objeto global. Se estiver quebrando seu código em um IIFE como na seção Fora de tópico , você poderá passar thiscomo um parâmetro nomeado windowou globalobter uma referência direta ao objeto global.
var a = 0; automaticamente se torna uma propriedade do objeto global. Se eu declarar var b = 0;em uma declaração de função, ela também será propriedade de algum objeto subjacente?
Mantendo simples:
a = 0
O código acima fornece uma variável de escopo global
var a = 0;
Esse código fornecerá uma variável a ser usada no escopo atual e, sob ela
window.a = 0;
Isso geralmente é igual à variável global.
a sob o escopo atual. Você pode. Além disso, seu uso da "variável global" é um pouco complicado - os dois lugares que você diz "variável global" não são mais globais do que o lugar que você não diz.
<title>Index.html</title>
<script>
var varDeclaration = true;
noVarDeclaration = true;
window.hungOnWindow = true;
document.hungOnDocument = true;
</script>
<script src="external.js"></script>
/* external.js */
console.info(varDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(noVarDeclaration == true); // could be .log, alert etc
// returns false in IE8
console.info(window.hungOnWindow == true); // could be .log, alert etc
// returns true in IE8
console.info(document.hungOnDocument == true); // could be .log, alert etc
// returns ??? in IE8 (untested!) *I personally find this more clugy than hanging off window obj
Existe um objeto global no qual todos os vars são pendurados por padrão? por exemplo: 'declaração globals.noVar'
window.*declaração. Essa declaração parece mais segura contra copiar e colar seu código e também limpa.
Com base na excelente resposta de TJ Crowder : ( Fora de tópico: Evite a confusãowindow )
Este é um exemplo de sua ideia:
Html
<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="init.js"></script>
<script type="text/javascript">
MYLIBRARY.init(["firstValue", 2, "thirdValue"]);
</script>
<script src="script.js"></script>
</head>
<body>
<h1>Hello !</h1>
</body>
</html>
init.js (Com base nesta resposta )
var MYLIBRARY = MYLIBRARY || (function(){
var _args = {}; // private
return {
init : function(Args) {
_args = Args;
// some other initialising
},
helloWorld : function(i) {
return _args[i];
}
};
}());
script.js
// Here you can use the values defined in the html as if it were a global variable
var a = "Hello World " + MYLIBRARY.helloWorld(2);
alert(a);
Aqui está o plnkr . Espero que ajude!
No escopo global, não há diferença semântica.
Mas você realmente deve evitar a=0 desde que você defina um valor para uma variável não declarada.
Use também fechamentos para evitar a edição do escopo global
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
Sempre use fechos e iça para o escopo global quando for absolutamente necessário. Você deve usar a manipulação de eventos assíncrona para a maior parte de sua comunicação.
Como o @AvianMoncellor mencionou, há um bug do IE com var a = foo apenas uma declaração global para o escopo do arquivo. Esse é um problema com o notório intérprete quebrado do IE. Esse bug parece familiar, provavelmente é verdade.
Então fique com window.globalName = someLocalpointer
deleteum var).
var. Eles são mecanismos completamente diferentes que têm praticamente o mesmo resultado prático. :-)
varpula para a parada do escopo.