Комментарии 43
Подробное описание работы функций в стандарте ECMA-262-3.
+2
Объявить такую функцию можно двумя, по сути, эквивалентными способами.На самом деле, способов существенно больше. Правда, использовать их я бы не советовал.
+function(){console.log(5)}() // подставьте свой любимый оператор
1,function(){console.log(5)}() // подставьте своё любимое число, строку или ещё какое-нибудь выражение
[function(){console.log(5)}()]
Общее же правило таково: если функция является частью выражения, то она становится FunctionExpression и является выражением, т.е. её можно вызвать. Если же она не является частью выражения, то она является FunctionDeclaration и вызову не поддается. Например:
function fnc(){} // FunctionDeclaration
fnc = function(){} // FunctionExpression
Отсюда же получаем, что следующая запись вполне корректнаfnc = function(){return 5}()
Но лично я не советую её применять, поскольку для очень длинных функций становится не очевидно, что будет результатом выражения — то ли функция, то ли её значение (по-умолчанию предполагается первое).
По этой теме советую почитать статью на javascript.ru.
+6
Ну и да: тут скорее не объявление, а именно использование.
0
я может себе неправильно все это представляю но все эти три примера это по сути второй способ. + одновременно изварщение, специально для этогои написал «Если не обращать внимание на всякие извращения» :)
идея была просто в том чтобы показать какраз Function declaration и Function Expression так чтобы на практике было понятно. может не лучшим образом сделал конечно :)
идея была просто в том чтобы показать какраз Function declaration и Function Expression так чтобы на практике было понятно. может не лучшим образом сделал конечно :)
0
> Правда, использовать их я бы не советовал.
Мне тильда (битовый NOT) нравится в этом плане :)
Мне тильда (битовый NOT) нравится в этом плане :)
-1
НЛО прилетело и опубликовало эту надпись здесь
«Этого нельзя понять, это можно только запомнить!»
+1
Self defining function — это страшно читаемая вещь, а в обфусцированном коде это вообще как выстрел в голову!
+1
А не будет ли правильней в последнем примере с Currying делать
?
Чтобы правильно обрабатывался this и можно было использовать currying и для методов
return fn.apply( this, args );
?
Чтобы правильно обрабатывался this и можно было использовать currying и для методов
+1
Self defining function — до этой статьи, если бы я увидел подобный код, врядли бы догадался о намерениях писавшего. Так что… применение под вопросом. Но решение да, элегантное.
0
Не коснулись такой интересной темы как объявление рекурсивных функций. Например, у нас есть тупо факториал, который используется в куче кода:
ну или
Потом по каким-то причинам нам нужно
В итоге получается, что и вызовы factorial(5) и realFactorial(5) вываливают ошибку. Это получается, т.к. рекурсивный вызов factorial использует переменную из родительской области видимости, а там она переопределяется. В этом случае надо определять функцию так:
Ну или чтобы не путаться:
var factorial = function (n) {
return n === 1 ? 1 : factorial(n - 1) * n;
};
ну или
function factorial(n) {
return n === 1 ? 1 : factorial(n - 1) * n;
};
Потом по каким-то причинам нам нужно
var realFactorial = factorial;
factorial = function (n) {
throw 'please use realFactorial instead';
};
В итоге получается, что и вызовы factorial(5) и realFactorial(5) вываливают ошибку. Это получается, т.к. рекурсивный вызов factorial использует переменную из родительской области видимости, а там она переопределяется. В этом случае надо определять функцию так:
var factorial = function factorial (n) {
return n === 1 ? 1 : factorial(n - 1) * n;
};
Ну или чтобы не путаться:
var factorial = function f (n) {
return n === 1 ? 1 : f(n - 1) * n;
};
+5
var saySomethingClever;
(function(){
var appleTest = /Apple/i;
var googleTest = /Google/i;
if( appleTest.test(navigator.vendor) )
saySomethingClever = function(){ console.log("I love apples <3"); }
else if( googleTest.test(navigator.vendor) )
saySomethingClever = function(){ console.log("android is everything for me <3"); }
else saySomethingClever = function(){ console.log("i love this unpopular corporation too"); }
})();
saySomethingClever();
Пример тоже так себе. Тогда уж так:
var saySomethingClever = (function(){
var appleTest = /Apple/i;
var googleTest = /Google/i;
if( appleTest.test(navigator.vendor) )
return function(){ console.log("I love apples <3"); }
else if( googleTest.test(navigator.vendor) )
return function(){ console.log("android is everything for me <3"); }
else
return function(){ console.log("i love this unpopular corporation too"); }
})();
saySomethingClever();
Или, даже так:
var saySomethingClever = (function(){
var appleTest = /Apple/i,
googleTest = /Google/i;
return appleTest.test(navigator.vendor) ? function(){ console.log("I love apples <3") } :
googleTest.test(navigator.vendor) ? function(){ console.log("android is everything for me <3") } :
function(){ console.log("i love this unpopular corporation too") } ;
})();
saySomethingClever();
Раз уж рассказываете про такую тему, то сразу можно было привести пример этого-же без copy-paste:
var saySomethingClever = (function(){
var appleTest = /Apple/i,
googleTest = /Google/i,
log = function (message) {
return function(){ console.log(message) };
};
return appleTest.test(navigator.vendor) ? log("I love apples <3"):
googleTest.test(navigator.vendor) ? log("android is everything for me <3"):
log("i love this unpopular corporation too");
})();
saySomethingClever();
Как-то так, в общем.
+2
Т.к. третий пример поехал из-за ширины — его можно записать так:
var saySomethingClever = (function(){
var appleTest = /Apple/i,
googleTest = /Google/i;
return appleTest.test(navigator.vendor) ?
function(){ console.log("I love apples <3") } :
googleTest.test(navigator.vendor) ?
function(){ console.log("android is everything for me <3") } :
function(){ console.log("i love this unpopular corporation too") } ;
})();
saySomethingClever();
+1
первый пример действительно лучше. на мой взгляд с тренарным оператором код становится в данном случае менее читаемым. а вариант с функцией log хорош в этом случае но в качестве общего примера он неподходит, потому что если в ветках есть какиенибудь отличчия — он летит в трубу.
0
спасибо огромное — заменил пример в саттье на немного исправленный ваш первый.
0
Спасибо, очень интересно и позновательно. Но использовать их надо аккуратно, а-то потом коллеги по работе будут мучаться, если они не читали этот пост. :)
0
console.log( "sample b" );
b();
function b() { console.log(1); }
«ну хоть ты тресни», но FF и Chrome показали один и тот же результат
> sample b
> 1
даже если определение функции b() поставить в самом начале
0
ну да. я вроде бы так и написал, незаню как можно лучше было сформулировать. смысл примера b показать что в случае объявления именованной функции к ней можно обратиться даже до появления непосредственно строки с обьявлением.
0
Надо так и формулировать, что вызов функции можно осуществлять до её объявления.
Хотя тот же FF сказал «ай-яй-яй»:
Лично я понял, что вы примером пытались показать, что «1» выведется раньше, чем «sample b»
Хотя тот же FF сказал «ай-яй-яй»:
ReferenceError: b is not definedChrome скушал.
Лично я понял, что вы примером пытались показать, что «1» выведется раньше, чем «sample b»
0
пс. я с соседом читали статью и поняли одинаково. Может всё-таки дело в формулировке?
0
Спасибо сейчас уточню формулировку :)
по поводу второго коментария — фаерфокс неможет это нескушать, боюсь потому что это ожидаемое поведение от любого браузера :)
впрочем если вы вбивали это непосредственно через консоль фаербага то да могли быть проблемы.
по поводу второго коментария — фаерфокс неможет это нескушать, боюсь потому что это ожидаемое поведение от любого браузера :)
впрочем если вы вбивали это непосредственно через консоль фаербага то да могли быть проблемы.
0
угу в firebug. Даже если выполняется eval() разве должа быть какая-то разница с обычным кодом, запускаемым из загруженного файла?
+1
сказать по правде я с этим особенно не разбирался. в ближайшем будушем попробую это исправить :) но чисто эмпирически — мне кажется вполне — всетаки поведение именованных функций не совсем обычное. ну и фаербаг не всегда себя идеально ведет так что он может :)
0
я тут посмотрел на сообщение об ошибке в firebug. скорее всего при прогоне через консоль в фаербаге функция превращается в именованный function expression( это второй вариант в этой статье, только у меня он без имени, думал что так проще будет но вот этот момент упустил из виду конечно. )
ну вот типа этого a = function b() { console.log(2); }. и тогда она ведет себя как положенно для этого случая, но не так как мы ожидаем
ну вот типа этого a = function b() { console.log(2); }. и тогда она ведет себя как положенно для этого случая, но не так как мы ожидаем
0
Карринг для замыкания строки из двух букв даёт сомнительную экономию текста за счёт производительности.
Вот еслиб там был объект Author и в console.log передавалось author.toString() — жаверы 90ых бы заценили.
Вот еслиб там был объект Author и в console.log передавалось author.toString() — жаверы 90ых бы заценили.
+1
А ещё можно соорудить и само-пере-определяемую функцию, если её замкнуть в саму себя…
/** usage: * yield(N) -- (re)start yielding song * yield() -- continue/loop yielding */ var yield = function(more) { more = more||Math.ceil(Math.random()*3); (function(jack){ yield = function(nomore) { if( nomore || !more--) return (yield = jack)(); return "No more!"; } })(yield); return "Hit the road, Jack! And don't you come back!"; }
+4
var f = function() { console.log(1); }
f();
function f(){ console.log(2); }
f();
выдаст 1 и 2, а не две единицы, кстати
0
а, не, туплю — все верно
тут хук фбага
тут хук фбага
+1
вы, кстати, ошибаетесь. при выполнении через консоль может быть такой косяк потому что функция превращается в фанкшен экспрешен. каждый тест перед постом я проверяю как мнимум в двух браузерах.
0
Очень полезно и познавательно. Спасибо
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
JavaScript для чайников. Всё что вы хотели знать о функциях но боялись спросить