Разница между синтаксисами объявления переменных в Javascript (включая глобальные переменные)?
Есть ли разница между объявлением переменной:
var a=0; //1
...сюда:
a=0; //2
...или же:
window.a=0; //3
в глобальном масштабе?
5 ответов
Да, есть пара отличий, хотя на практике они обычно не большие.
Есть четвертый путь, а с 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
Эти заявления объяснили
# 1var a = 0;
Это создает глобальную переменную, которая также является свойством глобального объекта, к которому мы обращаемся как window
в браузерах (или через this
глобальная область, в нестрогом коде). В отличие от некоторых других свойств, свойство не может быть удалено через delete
,
В терминах спецификации он создает привязку идентификатора для объекта Environment Record для глобальной среды. Это делает его свойством глобального объекта, потому что в глобальном объекте хранятся привязки идентификаторов для объекта среды Запись среды. Вот почему свойство не удаляется: это не просто свойство, это привязка идентификатора.
Привязка (переменная) определяется до запуска первой строки кода (см. "Когда var
бывает "ниже).
Обратите внимание, что в IE8 и более ранних версиях свойство создано на window
не перечисляется (не отображается в for..in
заявления). В IE9, Chrome, Firefox и Opera его можно перечислить.
# 1,1let a = 0;
Это создает глобальную переменную, которая не является свойством глобального объекта. Это новая вещь с ES2015.
В терминах спецификации он создает привязку идентификатора в декларативной записи среды для глобальной среды, а не для объекта записи среды. Глобальная среда уникальна тем, что имеет разделенную запись среды, одну для всех старых вещей, которые идут в глобальный объект (запись среды объекта), и другую для всех новых вещей (let
, const
и функции, созданные class
), которые не идут на глобальный объект.
Привязка создается до того, как будет выполнен любой пошаговый код в включающем его блоке (в данном случае, до запуска любого глобального кода), но он никоим образом не будет доступен, пока пошаговое выполнение не достигнет let
заявление. Как только исполнение достигает let
утверждение, переменная доступна. (См. "Когда let
а также const
бывает "ниже.)
# 1,2const a = 0;
Создает глобальную константу, которая не является свойством глобального объекта.
const
в точности как let
за исключением того, что вы должны предоставить инициализатор (= value
часть), и вы не можете изменить значение константы после ее создания. Под одеялом это точно так же, как let
но с флагом привязки идентификатора, говорящим, что его значение не может быть изменено. С помощью const
делает три вещи для вас:
- Делает это ошибкой времени разбора, если вы пытаетесь присвоить константу.
- Документирует его неизменный характер для других программистов.
- Позволяет оптимизировать движок JavaScript, исходя из того, что он не изменится.
# 2a = 0;
Это создает свойство глобального объекта неявно. Поскольку это обычное свойство, вы можете удалить его. Я бы порекомендовал не делать этого, это может быть непонятно любому, кто читает ваш код позже.
И что интересно, опять же в IE8 и более ранних версиях свойство создано не перечисляемым (не отображается в for..in
заявления). Это странно, особенно учитывая № 3 ниже.
#3window.a = 0;
Это явно создает свойство глобального объекта, используя window
глобальный, который ссылается на глобальный объект (в браузерах; некоторые не браузерные среды имеют эквивалентную глобальную переменную, такую как global
на NodeJS). Поскольку это обычное свойство, вы можете удалить его.
Это свойство перечислимо в IE8 и более ранних версиях, а также в любом другом браузере, который я пробовал.
# 4this.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);
}
Как видите, символ foo
определяется перед первой строкой, но символ bar
нет. Где var foo = "f";
утверждение состоит в том, что на самом деле есть две вещи: определение символа, которое происходит до запуска первой строки кода; и выполнение присвоения этому символу, что происходит, когда строка находится в пошаговом потоке. Это известно какvar
поднимать "потому что var foo
часть перемещается ("поднимается") в верхнюю часть прицела, но foo = "f"
часть остается в своем первоначальном месте. (См. Бедный неправильно понялvar
в моем маленьком анемичном блоге.)
когда let
а также const
случаться
let
а также const
отличаются от var
несколькими способами. Способ, который имеет отношение к этому вопросу, заключается в том, что хотя определяемая ими привязка создается до запуска любого пошагового кода, она недоступна до let
или же const
заявление достигнуто.
Итак, пока это работает:
display(a); // undefined
var a = 0;
display(a); // 0
Это выдает ошибку:
display(a); // ReferenceError: a is not defined
let a = 0;
display(a);
Два других способа, которыми let
а также const
отличаться от var
, которые на самом деле не имеют отношения к вопросу:
var
всегда применяется ко всему контексту выполнения (во всем глобальном коде или в коде функции в той функции, в которой он появляется), ноlet
а такжеconst
применять только в блоке, где они появляются. То есть,var
имеет функцию (или глобальную) область видимости, ноlet
а такжеconst
иметь область видимости блокаповторяющий
var a
в том же контексте безвреден, но если у вас естьlet a
(или жеconst a
), имея другойlet a
илиconst a
илиvar a
это синтаксическая ошибка
Вот пример, демонстрирующий, что let
а также const
вступают в силу немедленно в их блоке до запуска любого кода в этом блоке, но не доступны до тех пор, пока let
или же const
заявление:
var a = 0;
console.log(a);
if (true)
{
console.log(a); // ReferenceError: a is not defined
let a = 1;
console.log(a);
}
Обратите внимание, что второй console.log
не сможет получить доступ к a
снаружи блока.
Не по теме: избегать загромождения глобального объекта (window
)
window
объект становится очень, очень загроможденным свойствами. По возможности, настоятельно рекомендуем не добавлять в беспорядок. Вместо этого оберните ваши символы в небольшую упаковку и экспортируйте не более одного символа в window
объект. (Я часто не экспортирую какие-либо символы в window
объект.) Вы можете использовать функцию для хранения всего вашего кода, чтобы содержать ваши символы, и эта функция может быть анонимной, если вам нравится:
(function() {
var a = 0; // `a` is NOT a property of `window` now
function foo() {
alert(a); // Alerts "0", because `foo` can access `a`
}
})();
В этом примере мы определяем функцию и выполняем ее сразу (()
в конце).
Функция, используемая таким образом, часто называется областью видимости. Функции, определенные в функции определения объема, могут обращаться к переменным, определенным в функции определения объема, потому что они являются замыканиями для этих данных (см. Закрытия не сложны в моем анемичном небольшом блоге).
Сохраняя это простым:
a = 0
Код выше дает глобальную переменную области видимости
var a = 0;
Этот код даст переменную, которая будет использоваться в текущей области видимости и под ней
window.a = 0;
Обычно это то же самое, что глобальная переменная.
<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'
Основано на превосходном ответе TJ Crowder: (Не по теме: избегать беспорядка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);
Вот плнкр. Надеюсь, это поможет!
В глобальном масштабе нет семантической разницы.
Но вы действительно должны избегать a=0
поскольку вы устанавливаете значение в необъявленную переменную.
Также используйте замыкания, чтобы вообще не редактировать глобальную область видимости.
(function() {
// do stuff locally
// Hoist something to global scope
window.someGlobal = someLocal
}());
Всегда используйте затворы и всегда поднимайте их в глобальную область, когда это абсолютно необходимо. В любом случае вы должны использовать асинхронную обработку событий для большей части вашего общения.
Как упомянул @AvianMoncellor, есть ошибка IE с var a = foo
только объявив глобальный для области видимости файла. Это проблема пресловутого сломанного интерпретатора IE. Эта ошибка звучит знакомо, так что, вероятно, это правда.
Так что придерживайтесь window.globalName = someLocalpointer