В JavaScript, имеет ли значение, если я вызываю функцию с круглыми скобками?
Я заметил разницу при вызове функции с пустыми скобками или вообще без скобок. Тем не менее, я не передаю никаких аргументов функции, поэтому я подумал, что будет разницей между:
window.onload = initAll();
а также
window.onload = initAll;
Пожалуйста, объясните принцип, стоящий за этим.
5 ответов
window.onload = initAll();
Это выполняет initAll()
сразу и присваивает возвращаемое значение функции window.onload
, Обычно это не то, что вы хотите. initAll()
придется вернуть функцию для этого, чтобы иметь смысл.
window.onload = initAll;
это назначает фактическую функцию window.onload
- это возможно, потому что в JavaScript, как говорит @Felix, функции являются объектами первого класса - без их выполнения. initAll
будет выполнен событием загрузки.
То, что говорит Пекка, правильно, но я хочу немного подробнее остановиться на примере, который поможет объяснить тому, кто не полностью понимает указатели функций или делегаты.
Я не буду использовать 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()
?
Функции в javascript являются гражданами первого класса, и поэтому могут быть назначены другим переменным или переданы в качестве аргументов.
Итак, когда вы делаете
window.onload = initAll;
Вы устанавливаете onload
собственность window
объект для ссылки на initAll
функционировать сам.
Когда вы делаете
window.onload = initAll();
Вы устанавливаете onload
свойство для хранения возвращаемого значения initAll, так как он будет выполняться на месте в этой строке.
Я опоздал на 6 лет, но я чувствую, что это можно объяснить гораздо проще, чем приведенные выше ответы.
Итак, вот TLDR; или с высоты птичьего полета при вызове функций, использующих и не использующих ()
"s
Давайте возьмем эту функцию, например:
function foo(){
return 123;
}
если вы войдете "фу" - без ()
console.log(foo);
---outout------
function foo(){
return 123;
}
Использование нет ()
означает получить саму функцию. Вы бы сделали это, если хотите, чтобы он передавался как обратный вызов.
если вы войдете "foo()" - с ()
console.log(foo());
-----output-----
123
С помощью ()
после функции означает выполнить функцию и вернуть ее значение.
initAll
является ссылкой на значение функции, а оператор скобок, добавленный к имени функции, запускает этот объект функции.
Так что если вы делаете что-то вроде
a = initAll
затем a
станет таким же, как initAll
- например, вы можете сделать a()
- но с
a = initAll()
переменная a
получит возвращаемое значение выполненного initAll
функция