Объявление vs инициализация переменной?

Мне любопытно узнать разницу между объявлением переменной и инициализацией переменной. например,

var example; // this is declaring

var example = "hi" // initializing? Or just "adding a value"?

Я не думаю, что я прав, но каково именно определение каждого? Или они в принципе означают одно и то же?

7 ответов


Edit: @ThisClark сказал что-то в комментариях, и я пошел, чтобы доказать ему, что он ошибается, и после прочтения спецификации еще кое-что узнал:

вот информативный, за исключением спецификация:

A var оператор объявляет переменные, которые относятся к VariableEnvironment работающем контекста выполнения. Переменные Var создаются при создании экземпляра и инициализации содержащей их лексической среды к undefined при создании. [...] Переменной, определенной VariableDeclaration с инициализатором, присваивается значение AssignmentExpression ее инициализатора при выполнении VariableDeclaration, а не при создании переменной.

основываясь на моем прочтении этого, следующие пункты описывают поведение (и "правильное" использование терминов) , о котором вы спросили в своем вопросе:

  • A переменной (например, var foo) заставляет эту переменную быть создано как только создается" лексическая среда". Например, если эта переменная была определена в теле функции, эта функция является "лексической средой", и поэтому создание переменной совпадает с созданием самой функции.

  • очевидно, переменные может или не может быть создан с инициализатор (т. е. правое выражение, что возвращает начальное значение переменной). Однако это довольно нестандартное использование термина "начальное значение"... давайте покопаемся в этом немного больше:

  • технически, в примечаниях к спецификации здесь, все переменные инициализируются значением undefined:

    переменные создаются [...] и инициализируются в undefined

    акцент на "технически" там, так как это в значительной степени академический, если инициализатор также был предоставлен.

  • основываясь на том, что мы уже рассмотрели, следует понимать, что заявление var foo; может существовать в любом месте внутри тела функции и перемещение его в другое место внутри той же функции не повлияет на семантику выполнения самой функции (независимо от того, если/где любые фактические назначения или другие ссылки на foo иметь место). Если это все еще сбивает с толку, перечитайте предыдущий точки.

  • последний бит поведения является наиболее интуитивной частью, и это задание на инициализатор. Это назначение происходит, когда эта строка кода на самом деле выполнена (что, опять же, не тот же момент времени, когда переменная технически получила создано).

Итак, чтобы быстро резюмировать:

  • все переменной объявления (которые используют var) составляют всегда инициализации с undefined при инициализации их лексическое окружение.
  • эта инициализация, вероятно, не считается задание, в техническом смысле (ха, @ThisClark, вы были неправильно!!). :)
  • назначения являются легкой частью, поскольку они ведут себя так (и в данный момент времени), что вы ожидаете.

надеюсь, что это поможет (и что я этого не сделал ужасно неправильно истолковать спецификацию!).


@jmar777 ответ, безусловно, лучшее объяснение и разбивка спецификации. Тем не менее, я считаю, что для нас, практических учеников, немного иллюстративного кода полезно! ;)


Основная Идея

  • 'Declaration' делает переменную доступной во всей заданной области.
  • 'Assignment' дает переменной определенное значение в этом месте кода. Если вы пытаетесь присвоить значение переменной, которая никогда не объявлена в этой области или родительской области, то переменная неявно объявлена в глобальной области (равно набрав window.varName = value).
  • '' это то, что происходит "за кулисами" или "под капотом", так сказать. Во время выполнения все объявил переменные инициализации С начала задание of 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'.
}


эффекты "области" при объявлении / назначении

что делает разницу между объявлением и присвоением еще более ясной, так это то, что объявления переменная всегда создает новую переменную в текущей области (myVarscopeB), даже если переменная то же имя уже существовало в родительской области (myVarscopeA). Тогда мы сможем присвоить новое значение myVarscopeB в любой момент текущей области без повторного объявления. (Это назначение не влияет на значение myVarscopeA.) Однажды конец scopeB достигается, myVarscopeB не будет дольше быть доступным для назначения.

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

таким образом, переменная должна быть объявлена только один раз за пределы, С каждым объявлением, переопределяющим любые объявления, сделанные в родительских областях (т. е. он создает отдельную переменную). Но это!--25-->должны быть объявленным в области, если он должен быть уникальным для этой области. Присвоение может происходить столько раз, сколько требуется, но влияет только на самую "близко объявленную" переменную (из-за отсутствия лучшего термина).


объявление в основном означает введение нового объекта в программу. Инициализация-это предоставление переменной первого значения. Таким образом, в основном ваш приведенный выше пример верен.


объявление-Это введение нового имени в программу.

var test;        // Is this a declaration ?

инициализация относится к "присвоению" значения.

var test = {first:"number_one"}  // Now that object is initialized with value

единственная разница в том, что var заявление инициализировать любые объявленные переменные без значения!--1-->.

в обоих примерах, вы объявляете переменную.

если вы присваиваете значение переменной без 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.

причина в том, чтобы разверните область переменной.

например, предположим, что переменная требуется в строке 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: Это просто тривиальный пример использования.


взято прямо из MDN: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined:

свойство global undefined представляет значение примитива undefined. Это один из примитивных типов JavaScript.

просто объявление переменной в Javascript, например var example инициализирует его до примитивного значения undefined. Это означает, что следующие два выражения эквивалент:

//equivalent expressions
var ex1;
var ex2 = undefined;

//true!
alert(ex2 === ex1);

что я не знаю и не могу проверить в это время, как далеко в истории веб-браузера предупреждение будет отображаться true. Например, это предупреждение работает в IE6 или каком-то неясном телефоне Blackberry? Я не могу сказать наверняка, что это универсально, но он, по крайней мере, работает в последних версиях Firefox, Chrome и Safari на момент написания.