Разница между синтаксисами объявления переменных в Javascript (включая глобальные переменные)?

Есть ли разница между объявлением переменной:

var a=0; //1

... следующим образом:

a=0; //2

... или:

window.a=0; //3

в глобальной области?

Ответ 1

Да, есть несколько отличий, хотя на практике они обычно не большие.

Там четвертый способ, а ES2015 (ES6) - еще два. Я добавил четвертый путь в конце, но вставил ES2015 после # 1 (вы увидите, почему), поэтому мы имеем:

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;

Это создает глобальную переменную, которая также является свойством Запись среды для глобальная среда. Это делает его объектом глобального объекта, потому что глобальный объект - это привязка идентификаторов для записи Environment Environment Environment. Вот почему свойство не является удаляемым: это не просто свойство, это привязка идентификатора.

Связывание (переменная) определяется до начала первой строки кода (см. "Когда var происходит" ниже).

Обратите внимание, что в IE8 и ранее свойство, созданное на window, не перечислимо (не отображается в операторах for..in). В IE9, Chrome, Firefox и Opera это можно перечислить.


# 1.1 let a = 0;

Это создает глобальную переменную, которая не является свойством глобального объекта. Это новая вещь с ES2015.

В спецификациях он создает привязку идентификатора в декларативной записи среды для глобальной среды, а не в записи среды объекта. Глобальная среда уникальна тем, что имеет разделенную запись среды, одну для всех старых вещей, которые идут по глобальному объекту (объектная запись среды), а другая для всех новых вещей (let, const) и созданных функций на class), которые не входят в глобальный объект.

Связывание создается до того, как будет выполнен любой пошаговый код в его охватывающем блоке (в этом случае, прежде чем запускается какой-либо глобальный код), но он не доступен никоим образом, пока пошаговое выполнение не достигнет let. Как только выполнение достигнет инструкции let, переменная доступна. (См. "Когда let и const произойдет" ниже.)


# 1.2 const a = 0;

Создает глобальную константу, которая не является свойством глобального объекта.

const точно соответствует let, за исключением того, что вы должны предоставить инициализатор (часть = value), и вы не сможете изменить значение константы после ее создания. Под обложками это точно как let, но с флагом в привязке идентификатора, говорящим, что его значение не может быть изменено. Использование const делает три вещи для вас:

  • Делает ошибку времени синтаксического анализа, если вы пытаетесь назначить константу.
  • Документирует его неизменный характер для других программистов.
  • Позволяет оптимизировать движок JavaScript на том основании, что он не изменится.

# 2 a = 0;

Это создает свойство в глобальном объекте неявно. Как нормальное свойство, вы можете удалить его. Я бы порекомендовал не делать этого, может быть неясно, кто будет читать ваш код позже.

И интересно, опять же, на IE8 и ранее, свойство, созданное не перечислимым (не отображается в операторах for..in). Это странно, особенно учитывая № 3 ниже.


# 3 window.a = 0;

Это создает свойство в глобальном объекте явно, используя глобальный объект window, который ссылается на глобальный объект (в браузерах, некоторые не-браузерные среды имеют эквивалентную глобальную переменную, например global на NodeJS). Как нормальное свойство, вы можете удалить его.

Это свойство перечислимо, в IE8 и более ранних версиях, а также в каждом другом браузере, который я пробовал.


# 4 this.a = 0;

Точно как # 3, за исключением того, что мы ссылаемся на глобальный объект через this вместо глобального window. Однако это не будет работать в строгом режиме, потому что в строгом режиме глобального кода this не имеет ссылки на глобальный объект (вместо этого он имеет значение undefined).


Удаление свойств

Что я подразумеваю под "удалением" или "удалением" a? Именно это: Удаление свойства (целиком) с помощью ключевого слова delete:

window.a = 0;
display("'a' in window? " + ('a' in window)); // displays "true"
delete window.a;
display("'a' in window? " + ('a' in window)); // displays "false"

delete полностью удаляет свойство из объекта. Вы не можете сделать это с помощью свойств, добавленных в window косвенно через var, delete либо молча игнорируется, либо генерирует исключение (в зависимости от реализации JavaScript и в строгом режиме).

Предупреждение: IE8 снова (и предположительно ранее, и IE9-IE11 в режиме "сломанной совместимости" ): он не позволит вам удалять свойства объекта window, даже если вы должно быть разрешено. Хуже того, это вызывает исключение, когда вы пытаетесь (попробовать этот эксперимент в IE8 и в других браузерах). Поэтому при удалении из объекта window вы должны быть защищены:

try {
    delete window.prop;
}
catch (e) {
    window.prop = undefined;
}

Это пытается удалить свойство, и если выбрано исключение, он делает следующее лучшее и устанавливает свойство undefined.

Этот только относится к объекту window и только (насколько я знаю) к IE8 и ранее (или IE9-IE11 в режиме "сломанной совместимости" ). Другие браузеры прекрасно удаляют свойства window, подчиняясь указанным выше правилам.


Когда var происходит

Переменные, определенные с помощью оператора var, создаются до запуска любого пошагового кода в контексте выполнения, поэтому свойство существует задолго до инструкции var.

Это может ввести в заблуждение, поэтому давайте посмотрим:

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"

Живой пример:

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"

function display(msg) {
  var p = document.createElement('p');
  p.innerHTML = msg;
  document.body.appendChild(p);
}

Ответ 2

Сохранение простоты:

a = 0

В приведенном выше коде содержится глобальная переменная области видимости

var a = 0;

Этот код даст переменную, которая будет использоваться в текущей области, и под ней

window.a = 0;

Это вообще то же самое, что и глобальная переменная.

Ответ 3

<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

Существует ли глобальный объект, по которому все вары отключены по умолчанию? например: 'globals.noVar declaration'

Ответ 4

Опираясь на отличный ответ T.J. Crowder: (Off-topic: избегайте загромождения window)

Это пример его идеи:

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 (на основе этого ответа)

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);

Здесь plnkr. Надеюсь, что это поможет!

Ответ 5

В глобальном масштабе не существует семантической разницы.

Но вам действительно следует избегать a=0, так как вы устанавливаете значение необъявленной переменной.

Также используйте блокировки, чтобы вообще не редактировать глобальную область

(function() {
   // do stuff locally

   // Hoist something to global scope
   window.someGlobal = someLocal
}());

Всегда используйте блокировки и всегда поднимайте их в глобальную область, когда это абсолютно необходимо. Вы должны использовать асинхронную обработку событий для большей части вашего общения.

Как заметил @AvianMoncellor, есть ошибка IE с var a = foo, объявляющая глобальную область для файла. Это проблема с IE пресловутым сломанным интерпретатором. Эта ошибка звучит знакомо, поэтому, вероятно, это правда.

Итак, придерживайтесь window.globalName = someLocalpointer