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

105

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

window.onload = initAll();

и

window.onload = initAll;

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

Декан
источник
24
@JS Bangs - только на английском языке (США); нигде больше. Хотя программисты часто называют их «круглыми скобками», чтобы избежать путаницы, в британском английском языке закругленные буквы называются просто скобками. Квадратные известны как «квадратные скобки». en.wikipedia.org/wiki/Bracket
Роб Левин,
13
Если серьезно, официальное имя UNICODE - Круглая скобка. 0028 ( ЛЕВАЯ скобка = открывающая скобка (1.0) и 0029 ) Правая скобка = закрывающая скобка (1.0) - unicode.org/charts/charindex.html#P и что Dictionary.com говорит об этом - dictionary.reference.com/ browse / PARENTHESIS «Одна или обе прямые изогнутые линии, () ...»
8
Так что это не просто «американский английский», это определение международного стандарта, потому что UNICODE - это международный стандарт.
2
@fuzzy - Серьезно, откуда вы берете факты? {}называются беличьими скобками.
Anurag
7
@fuzzy lollipop - Юникод - это международный стандарт кодирования символов в байтах, а не именования. Авторы документа Unicode не утверждают, что данное имя персонажа является международным стандартом. Это код и символ, который они определяют. Но вы могли бы отметить, что они также относятся к [и] как к квадратным скобкам - (а не только к «скобкам»), и что они относятся ко всем [, {и (как к скобкам. Вы должны стремиться понять нюансы в том, как в разных местах используются одни и те же слова. Очень важно, если вы являетесь частью международной команды.
Роб Левин,

Ответы:

161
window.onload = initAll();

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

window.onload = initAll;

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

Пекка
источник
18
Здесь важно отметить, что функции - это объекты первого класса в JavaScript.
Felix Kling
136

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

Я не буду использовать, 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чем ваша собственная функция. Единственное немного другое - это то, что он вызывается окном при загрузке. [Отказ от ответственности: я никогда не отменял оконные функции, поэтому я не уверен, что это приведет к негативным последствиям. Можно было бы надеяться, что они проверят, назначена ли функция перед ее вызовом, т.е. 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()?

BenAlabaster
источник
Замечательный ответ!
Шади Альмосри
Эй, а что, если я хочу добавить функцию, которая принимает аргументы в прослушивателе событий?
Шемирот
16

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

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

window.onload = initAll;

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

Когда ты делаешь

window.onload = initAll();

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

Питер Бейли
источник
10

initAll - это ссылка на значение функции и оператор скобок, добавленный к имени функции. ЗАПУСКАЕТ этот объект функции.

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

a = initAll

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

a = initAll()

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

Андрис
источник
8

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

Итак, вот TLDR ; или птичьего полета при вызове функции с использованием и без использования ()«S

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

function foo(){
return 123;
}

если вы войдете в "foo" - без ()

console.log(foo); 

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

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


если вы зарегистрируете "foo ()" - с ()

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

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

Garrettmac
источник