Объявление против инициализации переменной?
Мне любопытно узнать разницу между объявлением переменной и инициализацией переменной. например
var example; // this is declaring
var example = "hi" // initializing? Or just "adding a value"?
Я не думаю, что я прав, но каково определение каждого? Или они в основном означают одно и то же?
10 ответов
Редактировать: @ThisClark сказал что-то в комментариях, и я пошел, чтобы доказать, что он неправ, и после прочтения спецификации я узнал кое-что еще:
Вот информативно, кроме как из спецификации:
var
оператор объявляет переменные, которые находятся в области VariableEnvironment запущенного контекста выполнения. Переменные var создаются, когда создается экземпляр их содержащей Lexical Environment и инициализируетсяundefined
когда создан. [...] Переменной, определенной посредством VariableDeclaration с Initializer, присваивается значение AssignmentExpression его Initializer при выполнении VariableDeclaration, а не при создании переменной.
Исходя из моего прочтения, следующие пункты описывают поведение (и "правильное использование" терминов), о котором вы спрашивали в своем вопросе:
Объявление переменной (например,
var foo
) вызывает создание этой переменной, как толькосоздается лексическая среда. Например, если эта переменная была определена в теле функции, эта функция является "лексической средой", и поэтому создание переменной совпадает с созданием самой функции.Очевидно, что объявления переменных могут создаваться или не создаваться с помощьюинициализатора(т. Е. Правого выражения, которое разрешается до начального значения переменной). Это довольно неопределенное использование термина "начальное значение", хотя... давайте углубимся в это немного подробнее:
Технически, согласно примечаниям спецификации здесь, все переменные инициализируются значением
undefined
:переменные создаются [...] и инициализируются как неопределенные
Упор делается на "технически", так как это в значительной степени академично, если также был предоставленинициализатор.
Исходя из того, что мы уже рассмотрели, следует понимать, что утверждение
var foo;
может существовать где угодно в теле функции, и перемещение его в другое место в пределах той же функции не будет влиять на семантику времени выполнения самой функции (независимо от того, где / где имеются какие-либо фактические назначения или другие ссылки наfoo
происходить). Если это все еще сбивает с толку, перечитайте предыдущие пункты.Последний бит поведения является наиболее интуитивной частью, и это назначениеинициализатора. Это присваивание происходит, когда эта строка кода фактически выполняется(что, опять же, не является тем же моментом времени, когда техническисоздается переменная).
Итак, чтобы быстро резюмировать:
- Все объявления переменных (которые используют
var
) всегда инициализируются сundefined
при инициализации их лексической среды. - Эта инициализация, вероятно, не считается назначением в техническом смысле (ха, @ThisClark, вы ошиблись!!).:)
- Назначения являются легкой частью, так как они ведут себя так, как вы ожидаете.
Надеюсь, что это помогает (и что я не ужасно неправильно истолковал спецификации!).
Ответ @jmar777, безусловно, лучшее объяснение и разбивка спецификации. Тем не менее, я считаю, что для нас, практических учеников, немного иллюстративного кода полезно!;)
Основная идея
- "Декларация" делает переменную доступной во всей данной области.
- "Назначение" дает переменной конкретное значение в этом месте в коде. Если вы попытаетесь присвоить значение переменной, которая никогда не была объявлена в этой области или родительской области, то переменная неявно объявляется в глобальной области (равной типизации
window.varName = value
). - "Инициализация" - это то, что происходит, так сказать, "за кулисами" или "под капотом". Во время выполнения все объявленные переменные инициализируются с начальным присвоением
undefined
(даже если им сразу же присваивается другое значение в первой строке кода).
Таким образом, инициализация не имеет значения для нас. Мы объявляем и присваиваем, и движок Javascript инициализируется.
Итак, чтобы прямо ответить на пример в вашем вопросе:
var example;
объявляет переменную, которой присваивается значениеundefined
во время инициализации.var example = "hi"
объявляет переменную, которой также присваивается значениеundefined
изначально, но когда эта строка кода фактически достигается во время выполнения, она переопределяется на строку "hi".
Иллюстративный код
function testVariableDeclaration() {
// This behaves 'as expected'....
console.log(test2, 'no value assigned yet'); // --> undefined 'no value assigned yet'
// ....but shouldn't our actual expectation instead be that it'll throw an error since
// it doesn't exist yet? See the final console.log() below!
// As we all know....
test1 = 'global var'; // ....a variable assignment WITHOUT declaration in the current
// scope creates a global. (It's IMPLICITLY declared.)
// But a little counter-intuitively....
test2 = 'not global'; // Although this variable also appears to be assigned without
// declaration like 'test1', the declaration for 'test2' that
// appears *later* in the code gets hoisted so that it's already
// been declared in-scope prior to this assignment.
console.log( test1, window.test1 === test1 ); // --> 'global var' TRUE
console.log( test2, window.test2 === test2 ); // --> 'not global' FALSE
var test2; // As shown by the above console.log() outputs, this variable is scoped.
console.log( test3 ); // Throws a ReferenceError since 'test3' is not declared
// anywhere, as opposed to the first console.log() for 'test2'.
}
Влияние "Scope" на Декларирование / Назначение
Что делает разницу между объявлением и присваиванием еще более ясным, так это то, что объявление переменной всегда создает новую переменную в текущей области видимости (myVar
scopeB), даже если переменная с таким же именем уже существовала в родительской области видимости (myVar
сфера А). Тогда мы можем назначить новое значение myVar
scopeB в любой точке текущей области видимости без ее повторного объявления. (Это назначение не влияет на значение myVar
scopeA.) Как только достигнут конец scopeB, myVar
scopeB больше не будет доступен для назначения.
С другой стороны, если мы присваиваем значение переменной в заданной области, не объявляя ее в этой области, оно будет назначено следующему по величине объявлению в "цепочке областей действия" (или глобальное будет неявно объявлено, если не найдено более высокое объявление).
Таким образом, переменную необходимо объявлять только один раз для каждой области, причем каждое объявление переопределяет любые объявления, сделанные в родительских областях (т. Е. Она создает отдельную переменную). Но он должен быть объявлен в области видимости, если он должен быть уникальным для этой области. Назначение может происходить столько раз, сколько необходимо, но влияет только на наиболее "объявленную" переменную (из-за отсутствия лучшего термина).
Объявление: переменная регистрируется с использованием заданного имени в соответствующей области (например, внутри функции).
Инициализация: когда вы объявляете переменную, она автоматически инициализируется, что означает, что память для переменной выделяется механизмом JavaScript.
Присвоение: это когда переменной присваивается определенное значение.
let x; // Declaration and initialization
x = "Hello World"; // Assignment
// Or all in one
let y = "Hello World";
Источник: SitePoint
Разница лишь в том, что var
оператор будет инициализировать любые объявленные переменные без значения undefined
,
В обоих примерах вы объявляете переменную.
Если вы присваиваете значение переменной без var
утверждение, он будет идти вниз по цепочке области поиска в поисках объявленных переменных, в конечном итоге вернуться к глобальной window
объект.
Есть маленькая вещь, которую вы здесь упускаете. Аналогия с понятием концепции такова. Каждой переменной должно быть присвоено определенное значение.
Значение по умолчанию для всех переменных (если не указано явно, не определено)
1) let example; // this is declaring and initializing with undefined
2) example="hi"; // this is assigning the value to hi
3) let example = "hi" // this is declaring and initializing with "hi"
таким образом, 3-е утверждение фактически совпадает с 1+2.
Теперь может возникнуть вопрос: когда утверждение 3 возможно, зачем нам утверждение 1?
Причина заключается в расширении области действия переменной.
например, допустим, что переменная требуется в строке номер 8. Но это значение недоступно до позднего времени, и это тоже в блоке кода.
1) {
2) let a;
3) try{
4) a=someFunctionWhichMayThroeException();
5) }
6) catch(e){
7) a=100;
8) }
9) someFunctionOnA(a);// the variable is required here
10)
11) }
Объявляя переменную выше, мы увеличили область действия переменной, следовательно, ее можно использовать за пределами блока try.
PS: это всего лишь тривиальный пример использования.
var example; // this is declaring
var example = "hi" // initializing? Or just "adding a value"?
Это две вещи,
var example;
средство объявлено, а также инициализировано значением по умолчанию'undefined'
var example = "hi"
означаетexample
объявлен, а также инициализирован строкой"hi"
Декларация в основном означает введение новой программы в программу. Инициализация дает переменной ее первое значение. Таким образом, ваш приведенный выше пример верен.
Декларация
Объявление означает создание переменной. Каждая переменная, используемая в программе, должна быть объявлена.
Например:
-Вначале ему присваивается значение undefined
-Но когда эта строка кода действительно достигается во время выполнения, она переназначается на строку «hello».
Объявление - это введение нового имени в программу.
var test; // Is this a declaration ?
Инициализация относится к "присвоению" значения.
var test = {first:"number_one"} // Now that object is initialized with value
Взято прямо из MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined:
Глобальное свойство undefined представляет значение примитива undefined. Это один из примитивных типов JavaScript.
Просто объявив переменную в Javascript, такую как var example
инициализирует его примитивным значением undefined. Это означает, что следующие два выражения эквивалентны:
//equivalent expressions
var ex1;
var ex2 = undefined;
//true!
alert(ex2 === ex1);
На данный момент я не знаю и не могу проверить, насколько далеко в истории браузера появилось бы предупреждение. Например, работает ли это предупреждение в IE6 или в каком-то непонятном телефоне Blackberry? Не могу с уверенностью сказать, что это универсально, но, по крайней мере, оно работает в последних версиях Firefox, Chrome и Safari на момент написания статьи.