В JavaScript, имеет ли значение, если я вызываю функцию с круглыми скобками?

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

window.onload = initAll();

и

window.onload = initAll;

Пожалуйста, объясните принцип, лежащий в его основе.

Ответ 1

window.onload = initAll();

Этот выполняет initAll() прямо и присваивает возвращаемое значение функции window.onload. Обычно это не, что вы хотите. initAll() должен был бы вернуть функцию, чтобы это имело смысл.

window.onload = initAll;

это присваивает действительную функцию window.onload - это возможно, потому что в JavaScript, как говорит @Felix, функции являются объектами первого класса - без его выполнения. initAll будет выполняться событием загрузки.

Ответ 2

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

Я не буду использовать window.onload, потому что это немного придумано для демонстрации. Вместо этого я буду использовать функцию простого умножения:

function Multiply(operator, operand) {
    return operator * operand;
}

Это можно было бы записать:

Multiply = function(operator, operand) {
    return operator * operand;
}

Хотя в первом примере импликация может быть не очевидной, второй пример более ясно показывает, что мы назначаем функцию, которая имеет 2 параметра для переменной с именем Multiply, и это понятие функций как присвоений является общим в JavaScript. Это небольшая демонстрация того факта, что функции являются "гражданами первого класса", то есть они могут передаваться точно так же, как если бы мы проходили вокруг значений.

Итак, теперь к разнице присваивания:

var operator = 3;
var operand = 4;
var ret = Multiply(operator, operand);

В точке определения переменной ret выполняется Multiply и присваивается возвращаемое значение - ret становится равным 12.

Попробуйте еще раз по-другому:

var operator = 3;
var operand = 4;
var ret = Multiply;

Теперь, в точке определения ret, ret станет вашей функцией Multiply, а не результатом, полученным из вашей функции Multiply. Вызов ret() приведет к выполнению функции Multiply, и вы можете вызвать ее точно так, как если бы вы вызвали Multiply(operator, operand):

var out = ret(3, 4);

совпадает с

var out = Multiply(3, 4);

Вы эффективно сказали, что собираетесь использовать ret в качестве делегата для Multiply(). При вызове ret мы действительно ссылаемся на функцию Multiply.

Вернитесь к window.onload. Подумайте об этом как:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

initAll = function() {
    return 12;
}

Итак, как вы можете видеть, window.onload - это функция, как любая другая функция, в ней нет ничего особенного. Вы можете присвоить ему значение, назначить ему функцию, исключить ее, если хотите - дело в том, что нет ничего особенного в window.onload, чем о вашей собственной функции. Только немного отличается то, что он вызывается окном при его загрузке. [Отказ от ответственности: я никогда не отказывался от оконных функций, поэтому я не уверен, что это вызовет негативные последствия. Можно было бы надеяться, что они проведут проверку, назначена ли функция перед вызовом i.e. if (window.onload) window.onload();].

Теперь вызываем initAll() то, что мы говорим:

window.onload = initAll();

который мог бы также сказать:

window.onload = 12;

Но когда мы говорим initAll без круглых скобок, мы действительно говорим: я хочу заменить любую мою функцию window.onload, с новой функцией - т.е. я хочу заменить ее на initAll, так что любые вызовы window.onload запускают мой код initAll.

Итак:

window.onload = function() {
    //Doing what all good window.onload functions should do...
}

заменяется на:

window.onload = function() {
    return 12;
}

Таким образом, любой вызов window.onload будет выполнять вашу функцию initAll вместо того, чтобы изначально был window.onload. Вы заменили исходную функцию своей новой функцией.

На самом деле вы могли бы написать:

window.onload = function() {
    //Write all your init code right in here instead of having a separate 
    //initAll function.
}

Другим примером, который может быть лучше продемонстрирован, является следующее:

var d = new Date();
var currentTime = d.getTime();

Независимо от того, какое время было в момент времени d определено, оно назначается на currentTime. Отлично, но это полезно только в том случае, если мы хотим узнать, в какое время была вызвана функция, содержащая этот код, т.е. Во время загрузки страницы. Что, если мы хотим, чтобы текущее время в любое время вызывалось currentTime?

var currentTime = function() {
    var d = new Date();
    return d.getTime();
}

var a = currentTime(); //The current time at the point a is defined...
var b = currentTime;   //b is a functional reference to currentTime...
var c = b(); //The current time when variable c is defined
var d = c; //The current time when variable c was defined

Обратите внимание, как мы называем b() в наших c и d назначениях точно так же, как мы могли бы назвать currentTime()?

Ответ 3

Функции в javascript являются первоклассными гражданами и как таковые могут быть назначены другим переменным или переданы в качестве аргументов.

Итак, когда вы делаете

window.onload = initAll;

Вы устанавливаете свойство onload объекта window для ссылки на функцию initAll.

Когда вы делаете

window.onload = initAll();

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

Ответ 4

initAll - это ссылка на значение функции, а оператор скобок, добавленный к имени функции, запускает этот функциональный объект.

Итак, если вы делаете что-то вроде

a = initAll

то a станет таким же, как initAll - например, вы можете сделать a() - но с

a = initAll()

переменная a получит возвращаемое значение выполняемой функции initAll

Ответ 5

Я опаздываю на 6 лет, но я чувствую, что это могло быть объяснено намного проще, чем приведенные выше ответы.

Итак, вот TL;DR; или птичий глаз при вызове функций, использующих и не использующих ()

Возьмем эту функцию, например:

function foo(){
return 123;
}

, если вы запишете "foo" - без ()

console.log(foo); 

---outout------
function foo(){
return 123;
}

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


, если вы запишете "foo()" - с помощью ()

console.log(foo());
-----output-----
 123

Использование () после того, как функция означает выполнение функции и вернуть значение.