2014-11-04 4 views
2

У меня вопрос о переменной подъеме в Javascript.Javascript Variable hoisting example

Рассмотрим следующий пример;

var myName = "Richard"; // Variable assignment (initialization) 
​ 
​function myName() { 
console.log ("Rich"); 
} 
​ 
console.log(typeof myName); // string 

Я действительно смущен, почему typeof myName возвращается в виде строки .

Согласно моему пониманию, пример будет процитироваться, как показано ниже;

  1. Первая функция декларации (function myName()) получили бы водрузили на вершину, а затем
  2. JS интерпретатор будет читать строку var myName = "Richard" (поскольку функция объявления получает приоритет над объявлением переменной). Однако, поскольку уже будет свойство с именем «myName», это утверждение будет проигнорировано.

typeof myName Таким образом, необходимо получить возвращаются в функции (а не строки)

Пожалуйста, дайте мне знать, где мое понимание неверно.

ответ

1

JavaScript имеет систему динамического типа, то есть тип переменных может меняться со временем. В принципе, то, что вы пишете, правильно: во-первых, объявление функции запускается (при загрузке файла), но затем функция, хранящаяся в переменной myName, перезаписывается строкой.

Единственное, что игнорируется, это вызов var, так как переменная на самом деле уже объявлена.

Но это совершенно верно для . Перечислите переменную (и это то, что вы здесь делаете, назначив новое значение).

В конце концов, ваш образец ничего, кроме этого:

var x = 23; 
x = 'foo'; 

Это будет работать так же, x будет 'foo', и его тип будет string. Единственное отличие от вашего образца заключается в том, что в вашем случае используется значение типа function.

-1

Из-за Hoisting переменные и функции определений перемещаются к вершине, так что у вас есть:

var myName; 
// moved to top 
function myName() { 
    console.log ("Rich"); 
} 

// next your code 
myName = "Richard"; 

console.log(typeof myName); // string 

Если переписать код так:

var myName = "Richard"; // Variable assignment (initialization) 
​ 
myName = ​function() { // Variable redefinition 
    console.log ("Rich"); 
} 
​ 
console.log(typeof myName); // function 

Вашего myName переменный в настоящее время является потому что только переменная myName составляет hoisted:

var myName; 

myName = "Richard";  // Variable assignment (initialization) 
myName = ​function() { // Variable redefinition 
    console.log ("Rich"); 
} 
​ 
console.log(typeof myName); // outputs 'function' 
+0

Вы переходите от объявления функции к функции выражения в вашем примере и, к сожалению, они обрабатываются по-разному JavaScript: пока файл сканируется для деклараций функций при загрузке, выражения функций и их назначение разрешаются во время выполнения. Поэтому ваш пример, к сожалению, что-то объясняет, но не то, что было задано. –

+0

@GoloRoden - Я объяснил, почему тип переменной 'myName' является' string', а не 'function', затем я сделал пример, где тип переменной будет' function' ;-) –

-1

Идея «подъема» - это плохой способ понять, что происходит. Другими словами, по-моему, «подъем» - плохое объяснение подъема.

Что действительно происходит, это не «подъем».Что действительно происходит, так это то, что javascript выполняет код в два этапа: фазу компиляции и фазу eval. Сообщество javascript называет симптом этого «подъема», но большинство людей не понимают, почему подъемные тали, потому что они считают, что у переводчиков javascript есть такая функция, называемая «подъем» (они этого не делают).

Что на самом деле происходит, проще объяснить, чем идея подъема. Правила:

  1. Javascript всегда анализирует код сверху вниз. Он никогда не меняет код (он никогда не поднимается).

  2. Существует два этапа исполнения: компиляция и оценка.

  3. Все декларации обрабатываются на этапе компиляции, никакие выражения не будут оцениваться на этапе компиляции (потому что «оценка» выполняется на этапе оценки).

  4. Все выражения и все, что необходимо оценить, обрабатываются на этапе оценки.

Помните правило 1, все синтаксические разборки выполняются сверху вниз, и нет никакого возврата, нет подъема.

Давайте вашему примеру и попытаться понять его, держа в фазе компиляции и оценки ум в JavaScript:

var myName = "Richard"; // Variable assignment (initialization) 
​  
​ function myName() { 
     console.log ("Rich"); 
    } 

​ console.log(typeof myName); // string 
  1. В фазе компиляции, интерпретатор видит, что вы объявить переменную. Он выделяет область памяти для этой переменной и присваивает ей значение undefined.

  2. В фазе усложнения интерпретатор видит, что вы объявляете функцию. Он также отмечает, что имя функции затеняет имя переменной. Поэтому он создает функцию «myName» (это означает, что в этот момент переменная myName указывает на функцию).

  3. Фаза завершения компиляции. Теперь мы вводим этап оценки.

  4. На этапе оценки интерпретатор видит, что вы назначаете строку myName.

  5. Невозможно оценить, когда мы достигаем объявления функции, потому что декларации обрабатываются на этапе компиляции.

  6. На этапе оценки интерпретатор видит, что вы используете consoleof. myName. Поскольку последнее, что ему присвоено, это строка, в которой он печатает «string».

Обратите внимание, что если вы удалите задание строки, то myName будет TypeOf «функция». Это потому, что в этом случае последнее, что ему присвоено, является объявленной функцией.

Смотрите этот родственный вопрос для других тонкостей, вызванных двумя фазами выполнения: JavaScript function declaration and evaluation order

+1

Я не знаю, Думаю, ваше объяснение верное. «Подъем» - это языковая функция, и хотя стандарт не использует это самое слово, процедура точно документирована - см. «Активация привязки к заявлению» http://ecma-international.org/ecma-262/5.1/#sec -10,5 – georg

0

В дополнение к другим ответам, что следует отметить, что, если вы объявляете вашу функцию следующим образом:

var myName = function() { 
    console.log('Rich'); 
} 

или просто

myName = function(){ 
    console.log('Rich') 
} 

в отличие от "функции Myname..." синтаксис, то TypeOf Myname вернется «F помазание»

0

2 года прошло, но, возможно, это все-таки отношение к кому-то Вы правильно, при интерпретации объекта, это действительно так:

  • Сканирование контекст для объявления функций

    • Для каждой найденной функции создайте свойство в объекте переменной
    • Если имя функции уже существует, значение ссылочного указателя будет перезаписано
  • Сканирования контекста для объявления переменных

    • Для каждой переменной декларации найдены, создать свойство в переменном объекте, имя переменного и инициализировать значение как неопределенные
    • Если имя переменного уже существует в переменном объекте, ничего не делать и продолжать просмотр

Однако, похоже, это не поэтому для глобального масштаба. I.e. когда я определяю объект, результат точно так же, как и должен быть, когда я определяю то же самое в глобальной области, это не так. По-прежнему пытаюсь обернуть мою голову вокруг этого.