Autor Zpráva
anoim
Profil *
Ahoj,
četl jsem nějaké články o anonymních funkcích a uzávěrech a mám pocit jak kdyby ty informace byli protichůdné. Nebo jen nejasná formulace, že v tom teď mám bordel. Např. na Wikipedii jsem našel tuto formulaci, kde mi splývá v jedno anonymní, vnitřní funkce a uzávěr že teď nevím co je co:

Anonymní(vnitřní) funkce a uzávěry (closures)
Vnitřní funkce (neboli funkce definované uvnitř jiných (vnějších) funkcí) jsou vytvořeny při každém zavolání funkce nadřazené, a proměnné funkcí vnějších existují po dobu existence funkce vnitřní, dokonce i po ukončení zvolání (tedy i po navrácení této vnitřní funkce, má daná funkce stále přístup k proměnným své funkce vnější) – toto je mechanismus v JavaScriptu nazývaný jako closures - uzávěry.

V jiném článku jsem zase četl, že anonymní funkce je funkce, která je definovaná nebo volaná bez identifikátoru. Anonymní funkce jsou deklarovány pomocí operátoru funkce. Operátor funkce, můžete použít k vytvoření nové funkce.

Tak teď nevím jestli každá funkce která používá operátor je anonymní? A co tím operátorem bylo myšleno jestli klíčove slovo function nebo závorky ()? Jestli tedy skutečně anonymní funkce jsou pouze ty, které se nachází uvnitř jiné funkce. Taky se mi zdá, že ta definice z vyky není přesná, že tam schází, že tam musí být ta deklarace var myname = function ... Můžete mi tedy tyto věci potvrdit nebo vyvrátit? A ještě k těm uzávěrům. Znamená to, že anonymní funkce = uzávěr? Protože tak jsem to z Wiki pochopil, že vnitřní == anonymní funkce == uzávěr ... a tj. vnější funkce si uchovává proměnné i po skončení funkce. A nejsem si jistý, zda se proměnné z vnější dědí i to té vnitřní.

Dík za ujasnění.
Witiko
Profil
function a() {
  var a = 1;
  function b() {
    function c() {
      alert(a);
    }
  c();
  }
b();
}

a(); //1


Anonymní funkce = lokální funkce beze jména. Lokální proměnné a argumenty dané funkce jsou přístupné ze všech vytvořených anonymních funkcí. Lokální proměnné anonymních funkcí však nejsou přístupné z nadřazených funkcí, viz.:

function a() {
  function b() {
    var a = 1;
  }
  b();
  if(a) alert(a); // lokální proměnná a ve funkci a neexistuje
}


To však neznamená, že nelze měnit lokální proměnné funkce nadřazené.

function a() {
  var a = 1;
  function b() {
    a = 2;
  }
  b();
  alert(a); // 2
}


Operátor deklarace funkce, alias klíčové slovo je function stejně jako var je klíčové slovo deklarace proměnné.
Rozdíl mezi:

var a = function() {}

a

function a() {}


by být neměl, ale nechám se klidně opravit.

Uzávěry jsou výborné například i u tvorby prototypů. Konstruktor prototypu je funkce a proto si lze definovat privátní proměnné objektu ke kterým mohou přistupovat jen funkce objektu.

Řešení přidávání skóre bez uzávěru s veřejnou proměnnou:

var Score = function() {
  this.score = 0;
}
Score.prototype.increase = function(amount) {
  this.score += amount;
}


Pokud není důvod, aby byla proměnná veřejná a šla zevně editovat, je toto řešení lepší:

var Score = function() {
  var score = 0;
  this.increase = function(amount) {
    score += amount;
  }
}


this.increase je v tomto případě anonymní funkce, ačkoliv je veřejná.

V této ukázce je increase anonymní privátní zevně objektu nepřístupná funkce:
var Score = function() {
  var score = 0;
  var increase = function(amount) {
    score += amount;
  }
  this.plusDeset = function() {
    increase(10);
  }
}
anoim
Profil *
Witiko:
Tak nejdříve se vyjádřím k začátku (o uzávěrech jsem zatím nečet, přečtu později).

Jaký má vlastně smysl vytvářet ty funkce tak jak to děláš ty, tj. do jedné funkce vytvoříš další funkci, do ní další a do ní zase další? Má to nějakou výhodu? Jinak jsem teda pochopil ze článkům že tento příklad by bylo kratší realizovat tak, že by se ty funkce vložili jako argument, ale to teď rozebírat nechci (na to je ještě čas než to pochopím).

Takže z prvního příkladu jsem pochopil, že když se pokusím volat anonymní funkci c() z nadřazené funkce, tak se nedovolám, protože je to uvnitř anonymní funkce. Pak asi ale nechápu přesně to slovo lokální - není to relativní? Myslíš lokální, jako místní, tj. pouze ta jedna úroveň, kterou mám zrovna namysli, a , b nebo c. Pak jsou tedy všechny tři funkce anonymní, chápu to už konečně správně? Anebo se pletu, protože pokud platí že globální proměnné se deklarují na nejvyšší úrovni skriptu, tak tedy ta první funkce je globální, přístupná odkudkoliv, kdežto ty ostatní, které jsou uvnitř jsou anonymní. Ale kdybych je zkusil předem deklarovat jako globální, nezměnilo by se to?

var b;
var c;

function a() {
  var a = 1;
  function b() {
    function c() {
      alert(a);
    }
  }
c();
}

Hm. Nefunguje. Tak asi ne...


Takže k té větě co jsem někde vyčetl - že anonymní funkce "je funkce, která je definovaná nebo volaná bez identifikátoru." - tak to není pravda?
Witiko
Profil
Tak já to rozepíšu:

function a() {
  var a = 1; // definuji lokální proměnnou a
  function b() { // definuji lokální funkci b, která je vnořená do funkce a a má přístup k jejím argumentům a lokálním proměnným
    function c() { // definuji lokální funkci c, která je vnořená do funkce b a tím pádem i a a má přístup k jejím argumentům a lokálním proměnným
      alert(a); // pomocí alert() vypíšu lokální proměnnou a.
    }
  c();
  }
b();
}

// funkce b a c jsou lokální a jsou unikátní pro každé volání funkce. Mimo funkci neexistují - tzn. chovají se stejně jako lokální proměnné
// příklad má demonstrovat, že lokální funkce dědí lokální proměnné konstrukce ve které byla definována

a(); //1


anonymní funkce "je funkce, která je definovaná nebo volaná bez identifikátoru."
Anonymní funkce je název pro funkci lokální, která nemá žádné jméno. Řekněme, že předáš funkci setTimeout callback jako anonymní funkci:

setTimeout(function(){
  alert("a");
},1000)


Daná funkce nemá jméno, je definována přímo na místě použití, je proto anonymní. Co se funkciality týče, neliší se od funkce lokální, tu však deklarujeme se jménem a většinou ji použijeme vícekrát. Učebnicový příklad anonymní funkce je vyhodnocení výrazu na místě:

// anonymní funkce:

alert((function() {
  return 1+1;
})());


Výše zmíněná funkce nemá příliš praktických využití, ale chápeš co tím myslím.
anoim
Profil *
Poslední dva příklady chápu zcela jasně. Tam to jméno opravdu není. alert("a"). U toho prvního příkladu to bereš tak, že anonymní funkce je ta, která není přístupná z vnějšího prostředí? Čili je lokální. Protože všechny tři funkce mají jméno a, b, c . Ale rozdíl je v tom, že z nejvyšší úrovně skriptu se dovoláš jen a.
anoim
Profil *
Dívám se, že ještě nerozumím tomu, proč u posledního příkladu jsou uvnitř funkce alert ty první závorky? Když je smažu tak se nic nestane:

alert(function() {
return 1+1;
}());

Teď jsem si vzpomněl, že () je operátor volání funkce, tak snad proto?
anoim
Profil *
Tak už je mi to jasný, takže anonymní funkce, vnitřní funkce, lokální funkce a uzávěra je vše jedno a to samé. Tak dík za ochotu
Witiko
Profil
Vlastně ano, anonymní funkce je název pro lokální funkci, která nemá jméno. :) Rádo se stalo
habendorf
Profil
Witiko to zde popsal tak hezky, že bych link na toto vlákno navrhoval přidat sem: http://diskuse.jakpsatweb.cz/?action=vthread&forum=8&topic=106539, konkrétně do 3. bodu.
anoim
Profil *
Ještě jednu podstatnou věc si zapomněl zmínit (našel jsem zas na netu).

function say667() {
  var num = 666; // local
  var sayAlert = function() { 
  alert(num); // reference to local variable
  }
  num++;
  return sayAlert;
} 
var a = say667();
a();


Lokální proměnné se uchovávají jako odkaz, nikoliv jako kopie. Tady ten proces mi přijde dost zvláštní a nejsem si jist zda chápu co se v tomto příkladě děje. Nejdříve se vypočítá hodnota num v nadřazené funkci a pak se teprve spustí funkce sayAlert?
anoim
Profil *
Ještě jsem narazil na internetu na velice zajímavý komentář od Richarda Cornforda
Odkaz
Který upozorňuje na riziko anonymních funkcí při přiřazování vlastnostem objektů, že to může být nebezpečné z hlediska paměti.

The function expression option (3) is probably the easiest to write but
its drawback comes form the fact that function expressions are often
(usually) also inner functions and assigning them to properties of DOM
elements can induce the IE memory leak problem because of the closure
formed by the assignment. (lots of ways of avoiding that or negating the
harmful effects.)

It is also possible for the function referenced in the first approach to be an inner function, producing the same risks as the function expressions on IE. But usually the function referenced would be defined as a global function and that problem would not arise.
Witiko
Profil
Lokální proměnné se uchovávají jako odkaz, nikoliv jako kopie.
anoim:
Ne, lokální proměnné mohou i předávat pouze data. Zda je předáván pointer nebo data závisí na použitém typu dat. Objekty jsou vždy předávány formou reference, jsou referenčním datovým typem, funkce je v javascriptu objekt.

"Nejdříve se vypočítá hodnota num v nadřazené funkci a pak se teprve spustí funkce sayAlert?"
Vypočítá se num a vytvoří se funkce sayAlert, která danou proměnnou využívá. Funkce say667 tuto funkce navrátí. Příklad má být ukázkou toho, že dojde k zachování lokální proměnné num i po ukončení funkce, dokud existují aktivní odkazy, pak anonymní funkci i proměnnou sežere garbage collector.

Richarda Cornford je mírně všeobecný. Pokud vím, tak k memory leakům dochází pouze při použití u posluchačů událostí na elementech v Internet Exploreru, jehož garbage collector se v takovém případě zacykluje a resources neuvolní.
Yur4Y
Profil
Witiko:
Rozdíl mezi:
var a = function() {}
a
function a() {}
by být neměl, ale nechám se klidně opravit.
Asi to v tomto vlákne ešte nikto nespomínal, tak to poviem ja. Príkaz function (druhý prípad) na rozdiel od operátoru function (prvý) prebehne pred tým, ako sa spustí samotný kód. To znamená, že:
a(); //prebehne kvôli 3.riadku
b(); //vyhodí výnimku, pretože príkaz var sa "nepredbieha"
function a() { }
var b = function() {}
Podobne v niektorých prehliadačoch:
if (false)
{
  function x() {}
}
typeof x; //"function" v IE a Opere
ale
if (false)
{
  var x = function() {}
}
typeof x; //"undefined" všade
_es
Profil
Yur4Y:
Ešte na doplnenie tvojho kódu:
Premenná b existuje už pri spustení kódu, tak ako premenná a.
No premenná a má už od začiatku hodnotu tú funkciu, zatiaľ čo premenná b má na začiatku hodnotu undefined a až vo 4. riadku je jej hodnotou funkcia.
S tým podmieneným definovaním funkcie to nemusí byť až také jednoduché: (treba vyskúšať rôzne prehliadače)
javascript:if(false){function x(){}}alert(("x" in this)+" "+typeof x);
javascript:if(false){var x = function(){}}alert(("x" in this)+" "+typeof x);
dosť odlišne sa v tomto smere voči iným prehliadačom správa FF.
Witiko
Profil
Yur4Y:
Příklad 1 ano, příklad 2 občas. Vím, že při hraní s tím se mi stávalo, že javascriptový runtime takto nadefinoval i funkce uvnitř podmínek, neberouce na ně jakýkoliv ohled; Viz. _esův příklad #1 na Webkit jádře.
_es
Profil
Witiko:
javascriptový runtime takto nadefinoval i funkce uvnitř podmínek, neberouce na ně jakýkoliv ohled
Definovanie funkcie tak, ako v príklade 1, odporuje správnej syntaxi, takže by nejaký prehliadač mohol zahlásiť aj syntaktickú chybu. Preto aj rôzne prehliadače na ten príklad majú rôzne výsledky - je to nedefinované chovanie.

Viz. _esův příklad #1 na Webkit jádře.
Rovnako sa správa aj Opera aj IE. Odlišne sa správa Firefox.

V príklade 2 to bude fungovať tak, ako keby bol mimo podmienky príkaz var x; a v podmienke príkaz x=hodnota;.

Vaše odpověď

Mohlo by se hodit

Neumíte-li správně určit příčinu chyby, vkládejte odkazy na živé ukázky.
Užíváte-li nějakou cizí knihovnu, ukažte odpovídajícím, kde jste ji vzali.

Užitečné odkazy:

Odkud se sem odkazuje


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0