Comments 43
Подробное описание работы функций в стандарте ECMA-262-3.
Объявить такую функцию можно двумя, по сути, эквивалентными способами.На самом деле, способов существенно больше. Правда, использовать их я бы не советовал.
+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.
Ну и да: тут скорее не объявление, а именно использование.
я может себе неправильно все это представляю но все эти три примера это по сути второй способ. + одновременно изварщение, специально для этогои написал «Если не обращать внимание на всякие извращения» :)
идея была просто в том чтобы показать какраз Function declaration и Function Expression так чтобы на практике было понятно. может не лучшим образом сделал конечно :)
идея была просто в том чтобы показать какраз Function declaration и Function Expression так чтобы на практике было понятно. может не лучшим образом сделал конечно :)
> Правда, использовать их я бы не советовал.
Мне тильда (битовый NOT) нравится в этом плане :)
Мне тильда (битовый NOT) нравится в этом плане :)
UFO just landed and posted this here
«Этого нельзя понять, это можно только запомнить!»
Self defining function — это страшно читаемая вещь, а в обфусцированном коде это вообще как выстрел в голову!
А не будет ли правильней в последнем примере с Currying делать
?
Чтобы правильно обрабатывался this и можно было использовать currying и для методов
return fn.apply( this, args );
?
Чтобы правильно обрабатывался this и можно было использовать currying и для методов
Self defining function — до этой статьи, если бы я увидел подобный код, врядли бы догадался о намерениях писавшего. Так что… применение под вопросом. Но решение да, элегантное.
Не коснулись такой интересной темы как объявление рекурсивных функций. Например, у нас есть тупо факториал, который используется в куче кода:
ну или
Потом по каким-то причинам нам нужно
В итоге получается, что и вызовы 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;
};
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();
Как-то так, в общем.
Т.к. третий пример поехал из-за ширины — его можно записать так:
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();
первый пример действительно лучше. на мой взгляд с тренарным оператором код становится в данном случае менее читаемым. а вариант с функцией log хорош в этом случае но в качестве общего примера он неподходит, потому что если в ветках есть какиенибудь отличчия — он летит в трубу.
спасибо огромное — заменил пример в саттье на немного исправленный ваш первый.
Спасибо, очень интересно и позновательно. Но использовать их надо аккуратно, а-то потом коллеги по работе будут мучаться, если они не читали этот пост. :)
console.log( "sample b" );
b();
function b() { console.log(1); }
«ну хоть ты тресни», но FF и Chrome показали один и тот же результат
> sample b
> 1
даже если определение функции b() поставить в самом начале
ну да. я вроде бы так и написал, незаню как можно лучше было сформулировать. смысл примера b показать что в случае объявления именованной функции к ней можно обратиться даже до появления непосредственно строки с обьявлением.
Надо так и формулировать, что вызов функции можно осуществлять до её объявления.
Хотя тот же FF сказал «ай-яй-яй»:
Лично я понял, что вы примером пытались показать, что «1» выведется раньше, чем «sample b»
Хотя тот же FF сказал «ай-яй-яй»:
ReferenceError: b is not definedChrome скушал.
Лично я понял, что вы примером пытались показать, что «1» выведется раньше, чем «sample b»
пс. я с соседом читали статью и поняли одинаково. Может всё-таки дело в формулировке?
Спасибо сейчас уточню формулировку :)
по поводу второго коментария — фаерфокс неможет это нескушать, боюсь потому что это ожидаемое поведение от любого браузера :)
впрочем если вы вбивали это непосредственно через консоль фаербага то да могли быть проблемы.
по поводу второго коментария — фаерфокс неможет это нескушать, боюсь потому что это ожидаемое поведение от любого браузера :)
впрочем если вы вбивали это непосредственно через консоль фаербага то да могли быть проблемы.
угу в firebug. Даже если выполняется eval() разве должа быть какая-то разница с обычным кодом, запускаемым из загруженного файла?
сказать по правде я с этим особенно не разбирался. в ближайшем будушем попробую это исправить :) но чисто эмпирически — мне кажется вполне — всетаки поведение именованных функций не совсем обычное. ну и фаербаг не всегда себя идеально ведет так что он может :)
я тут посмотрел на сообщение об ошибке в firebug. скорее всего при прогоне через консоль в фаербаге функция превращается в именованный function expression( это второй вариант в этой статье, только у меня он без имени, думал что так проще будет но вот этот момент упустил из виду конечно. )
ну вот типа этого a = function b() { console.log(2); }. и тогда она ведет себя как положенно для этого случая, но не так как мы ожидаем
ну вот типа этого a = function b() { console.log(2); }. и тогда она ведет себя как положенно для этого случая, но не так как мы ожидаем
Карринг для замыкания строки из двух букв даёт сомнительную экономию текста за счёт производительности.
Вот еслиб там был объект Author и в console.log передавалось author.toString() — жаверы 90ых бы заценили.
Вот еслиб там был объект Author и в console.log передавалось author.toString() — жаверы 90ых бы заценили.
А ещё можно соорудить и само-пере-определяемую функцию, если её замкнуть в саму себя…
/** 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!"; }
var f = function() { console.log(1); }
f();
function f(){ console.log(2); }
f();
выдаст 1 и 2, а не две единицы, кстати
а, не, туплю — все верно
тут хук фбага
тут хук фбага
вы, кстати, ошибаетесь. при выполнении через консоль может быть такой косяк потому что функция превращается в фанкшен экспрешен. каждый тест перед постом я проверяю как мнимум в двух браузерах.
Очень полезно и познавательно. Спасибо
Sign up to leave a comment.
JavaScript для чайников. Всё что вы хотели знать о функциях но боялись спросить