Почему я могу использовать функцию до того, как она определена в JavaScript?

Этот код работает всегда, даже в разных браузерах:

function fooCheck() {
  alert(internalFoo()); // We are using internalFoo() here...

  return internalFoo(); // And here, even though it has not been defined...

  function internalFoo() { return true; } //...until here!
}

fooCheck();

Однако я не смог найти ни одной ссылки на то, почему это должно работать. Я впервые увидел это в презентации Джона Ресига, но это было только упоминание. Нет никаких объяснений ни там, ни где-либо еще.

Может ли кто-нибудь просветить меня?

В более новых версиях firefox это не работает, если код находится в try / catch. Смотрите эту скрипку: jsfiddle.net/qzzc1evt

Joshua Smith 31.01.2015 01:11
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
179
1
64 807
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Я лишь немного использовал JavaScript. Я не уверен, что это поможет, но это очень похоже на то, о чем вы говорите, и может дать некоторое представление:

http://www.dustindiaz.com/javascript-function-declaration-ambiguity/

Ссылка уже не мертвая.

mwclarke 01.05.2016 00:28

Ссылка мертвая.

Jerome Indefenzo 14.12.2017 12:38

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

jkmartindale 07.08.2018 21:41

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

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

Тело функции «internalFoo» должно куда-то перемещаться во время синтаксического анализа, поэтому, когда код читается (также известный как синтаксический анализ) интерпретатором JS, создается структура данных для функции и присваивается имя.

Только позже, затем запускается код, JavaScript фактически пытается выяснить, существует ли "internalFoo" и что это такое, и можно ли его вызвать и т. д.

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

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

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

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

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

Ответ принят как подходящий

Объявление function является магическим и вызывает привязку его идентификатора до того, как что-либо в его кодовом блоке * будет выполнено.

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

Если вы изменили пример, чтобы сказать:

var internalFoo = function() { return true; };

это перестанет работать.

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

Это задокументировано в Стандарт ECMAScript, раздел 10.1.3. К сожалению, ECMA-262 не очень читаемый документ даже по стандартам!

*: содержащая функция, блок, модуль или скрипт.

Я думаю, это действительно не читается. Я только что прочитал раздел 10.1.3, который вы указали, и не понял, почему положения там вызывают такое поведение. Спасибо за информацию.

Edu Felipe 04.11.2008 19:16

@bobince Хорошо, я начал сомневаться в себе, когда не нашел ни единого упоминания термина «подъем» на этой странице. Надеюсь, в этих комментариях достаточно Google Juice ™, чтобы все исправить :)

Mathias Bynens 22.12.2011 16:43

Это популярная комбинация вопросов и ответов. Рассмотрите возможность обновления, добавив ссылку / отрывок на аннотированную спецификацию ES5. (Что немного доступнее.)

user166390 16.07.2012 21:58

В этой статье есть несколько примеров: JavaScript-Scoping-and-Hoisting

Lombas 11.11.2015 15:26

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

windmaomao 09.05.2020 17:59

По той же причине следующее всегда помещает foo в глобальное пространство имен:

if (test condition) {
    var foo;
}

На самом деле, это по совсем другим причинам. Блок if не создает область видимости, а блок function() всегда создает ее. Настоящая причина заключалась в том, что определение глобальных имен javascript происходит на этапе компиляции, так что даже если код не запускается, имя определяется. (Извините, что так долго комментировал)

Edu Felipe 20.07.2009 01:27

Это называется ПОДЪЕМ - вызов (вызов) функции до того, как она была определена.

Я хочу написать о двух разных типах функций:

Функции выражения и функции объявления

  1. Функции выражения:

    Выражения функций могут храниться в переменной, поэтому им не нужны имена функций. Они также будут называться анонимной функцией (функцией без имени).

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

    let lastName = function (family) {
     console.info("My last name is " + family);
    };
    let x = lastName("Lopez");
    

    Вот как это можно записать в ECMAScript 6:

    lastName = (family) => console.info("My last name is " + family);
    
    x = lastName("Lopez");
    
  2. Функции объявления:

    Функции, объявленные со следующим синтаксисом, не выполняются немедленно. Они «сохраняются для последующего использования» и будут выполнены позже, когда они будут вызваны (вызваны). Этот тип функции работает, если вы вызываете ее ДО или ПОСЛЕ того места, где он был определен. Если вы вызываете функцию объявления до того, как она была определена, подъемник работает правильно.

    function Name(name) {
      console.info("My cat's name is " + name);
    }
    Name("Chloe");
    

    Пример подъема:

    Name("Chloe");
    function Name(name) {
       console.info("My cat's name is " + name);
    }
    
let fun = theFunction; fun(); function theFunction() {} также будет работать (узел и браузеры)
fider 15.03.2019 12:54

Действительно ли подъем «вызывает функцию до ее определения»? Увеличение области действия объявленного имени таким образом, чтобы оно было определено для другого кода в этой области - примерно то, что делает JavaScript, чтобы позволить вам вызывать функцию до ее объявления, и это подъем.

Noah 01.12.2020 21:01

Другие вопросы по теме