Если функции в JS являются первоклассными, что позволяет их вызывать до их определения?

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

console.log(foo);
var foo = 'bar';

... не работает, тогда как это:

console.log(foo());
function foo() {
 return('bar');
}

... делает.

Тем не менее, это:

console.log(foo());
var foo = function() { return 'bar'; };

не работает, что более согласовано.

Что дает?

Ответы

Ответ 1

Потому что вы не сравниваете одно и то же. В вашем примере вы сравниваете объявление функции function foo()... с объявлением переменной и присваиванием в var foo = 'bar';

Более правильное сравнение было бы:

console.log(foo);
var foo = 'bar';

с

console.log(foo());
var foo = function() {
 return 'bar';
}

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

Объявление функции является особым в этом смысле, поскольку оно является как объявлением, так и выражением/присваиванием в одном выражении и тем самым поднимается вместе.

В качестве примера: вы можете посмотреть выражения типа:

console.log(foo);
var foo = 'bar';

как это:

var foo;
console.log(foo); //prints undefined
foo = 'bar';

и

console.log(foo());
var foo = function() {
 return 'bar';
}

как это:

var foo;
console.log(foo());
foo = function() {
 return 'bar';
}

Ответ 2

То, что вы испытываете, называется подъемом. При использовании объявления функции, например:

function foo() {}

foo будет перемещен в начало ближайшей области (функции).

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

var foo = function() {}

переменная foo будет перемещена в начало, но присваивание произойдет, когда это необходимо.

Подробнее...

Ответ 3

Объявления функций автоматически попадают в область видимости в JS

console.log(foo());
function foo() {
 return('bar');
}

фактически интерпретируется как

function foo() {
 return('bar');
}
console.log(foo());

второй бит кода работает таким образом, потому что foo - переменная, а не функция (она просто имеет анонимную функцию как значение). Переменные также наклонены вверх, поэтому

console.log(foo());
var foo = function() { return 'bar'; };

становится

var foo; //empty variable
console.log(foo()); //undefined
foo = function() { return 'bar'; }; //creates a function without name and assigns it to foo

Ответ 4

Объявление функции и объявление переменной всегда будут перемещены в начало области.

console.log(foo());
function foo() {
   return 'bar';
}

интерпретируется как:

function foo() {
   return 'bar';
}
console.log(foo());

console.log(foo());
var foo = function () {
   return 'bar';
};

интерпретируется как:

var foo;
console.log(foo());
foo = function () {
   return 'bar';
};