ugrás a tartalomhoz

JavaScript függvények

Poetro · 2011. Már. 30. (Sze), 08.57

A függvények a JavaScript nyelv talán legfontosabb elemei. Ugyanakkor a függvények azok, amik a legtöbb félreértés áldozatai. Ennek okán úgy gondolom érdemes tisztázni a függvények működését és használatát. A függvények a JavaScriptben elsődleges (first-class) típusok, azaz hozzárendelhetjük őket változókhoz és objektum tulajdonságokhoz, átadhatjuk őket paraméterként más függvényeknek, valamint egy függvény illetve metódus is térhet vissza függvénnyel (egy függvényt metódusnak nevezünk, ha az egy objektum tulajdonsága). A klasszikus programozási nyelvekhez képest (C/C++, Java, PHP) ez a megközelítés idegen, ez is okozhatja a sok problémát az értelmezéssel kapcsolatban.

Függvények létrehozása

Alapvetően háromféleképpen hozhatunk létre függvényeket:

  • függvény deklarációval (function declaration)
  • függvénykifejezéssel (function expression)
  • Function konstruktor használatával.

Függvény deklaráció

A függvények létrehozásának ez a módja talán a legelterjedtebb.

function peldaFuggveny(parameter) {
  // függvény törzs
}

Ez a formája a függvényeknek szinte teljesen megegyezik a klasszikus nyelvekben való felírással, azzal a különbséggel, hogy mivel a JavaScript egy szkript nyelv, ezért nincs megadva a változók típusa, valamint hogy a függvény milyen típusú változót ad vissza, sőt az sem, hogy egyáltalán ad-e vissza valamit.

A függvény deklaráció szabályai a következők:

  1. A függvény deklarációnak kötelezően van neve,
  2. vagy Program szinten, vagy egy másik függvény törzsében szerepel,
  3. akkor jön létre, amikor a program futása abba a környezetbe jut,
  4. módosítja a környezeti változók listáját (variables object).

Ebből a listából szerintem az első pont nem szorul magyarázatra. A 2. pont azt jelenti, hogy vagy a fő programkódban (böngésző esetén közvetlenül <script> elemben), illetve egy abban levő függvény törzsében szerepelhet. Például:

<script>
function peldaFuggveny1(parameter) {
  // függvény törzs
}
</script>

illetve

function foo() {
  function peldaFuggveny2() {
    // függvény törzs
  }
}

A 3. pont pedig azt jelenti, hogy a peldaFuggveny2() nevű függvény akkor jön létre, amikor a foo() függvény futása elkezdődik. Ezt a viselkedést – azaz, hogy a függvény felliftezik a környezet tetejére – nevezzük hoistingnak. Azaz:

function foo() {
  var bar = peldaFuggveny2(); // a függvény már létezik

  function peldaFuggveny2() {
    // függvény törzs
  }
}

A 4. pont szerint pedig az elérhető változók listája kibővül a függvény nevével. Azaz egy változóhoz hozzárendelhetjük a függvényt, valamint bármilyen más helyen, ahol kifejezést használhatunk, hivatkozhatunk a függvényre a nevével.

Függvénykifejezés

A függvénykifejezés (function expression) létrehozásának szabályai a következők:

  1. a kódban ott szerepelhet, ahol kifejezés szerepelhet,
  2. neve elhagyható,
  3. nem módosítja a környezeti változók listáját,
  4. akkor jön létre, amikor a program futása rákerül.

Úgy gondolom, hogy az 1. pont szorul a legnagyobb magyarázatra. Kifejezés szerepelhet függvények, illetve konstruktorok paramétereként, és mindenhol máshol, ahol változó szerepelhet. Mit jelent az, hogy a neve elhagyható? Hogyan hivatkozunk akkor majd a függvényünkre? Hát például úgy, hogy hozzárendeljük egy változóhoz, elvégre a függvények elsődleges típusok.

// Hozzárendelhetjük változókhoz.
var foo = function () {
      // függvény törzs
    };
// Átadhatjuk paraméterként.
foo(function () {
  // függvény törzs
});

Ha a függvénykifejezésnek adhatunk nevet, de nem módosítja a környezeti változókat, akkor mire jó? Arra, hogy hivatkozni tudjunk rá a függvényünkön belül.

var foo = function bar(foobar) {
      if (foobar) {
        bar(!foobar);
      }
    };
Azonnal meghívott függvénykifejezés

A függvénykifejezés egyik speciális fajtája az azonnal meghívott függvénykifejezés (Immediately-Invoked Function Expression, IIFE), vagy ahogy tévesen régebben nevezték self-executing anonymous function illetve self-invoked anonymous function. Ennek lényege, hogy a függvénykifejezést azonnal meghívjuk.

(function () {
  // függvény törzs
})();

Hogyan is működik ez, és miért? A zárójelek hatására a függvényünk függvénykifejezés lesz, mivel a zárójeleken belül csak kifejezés szerepelhet (amennyiben a függvény már eleve olyan helyen szerepel, ahol csak kifejezés szerepelhet, a zárójelek elhagyhatók). Ezt a létrejött függvénykifejezést pedig azonnal meg is hívjuk.

(function foo(bar) {
  if (bar) {
    foo(false);
  }
})('foobar');

Mint látható az azonnal meghívott függvénykifejezésnek nem kell anonimnak lennie, ha hivatkozni szeretnénk rá belülről, akkor adhatunk neki nevet is. Még egyszer tekintsük át, mi is történik itt valójában:

  1. Létrehozunk egy függvénykifejezést, aminek foo a neve, de kívülről nem elérhető.
  2. A függvénykifejezést meghívjuk 'foobar' paraméterrel.
  3. A függvénykifejezés meghívja magát még egyszer (most már false paraméterrel), mivel tud saját magára hivatkozni a nevével.
Miért hasznosak a függvénykifejezések?

Használatukkal elkerülhetjük a globális névtér változókkal való telepiszkítását. Ugyanis a függvényen belül var kulcsszóval létrehozott változók a függvényen kívül nem léteznek. Ugyanakkor a függvényünk azonnal lefut, és még a függvény a saját nevével se szennyezi a globális névteret, mivel a függvénykifejezés neve nem kerül a környezeti változók közé.

JScript és a függvénykifejezések

Az Microsoft JavaScript implementációja (JScript) nem specifikáció szerint működik, amikor függvénykifejezések nevéről van szó. Ugyanis ha egy függvénykifejezésnek nevet adunk, akkor azt a JScript függvény deklarációnak gondolja teljesen hibásan, azaz a környezeti változók közé is bekerül a függvény. Ezért amennyiben Internet Explorer, vagy más JScript felhasználás is a megcélzott platformok között van, akkor bánjunk óvatosan a függvénykifejezések elnevezésével (például ne ütközzön változó, vagy függvénynevekkel).

Function konstruktor

Mivel a Function konstruktor használata kerülendő, nem is foglalkozunk vele túl sokat, igazából csak az alapokat szeretném bemutatni.

var foo = new Function('bar', 'foobar', 'return bar + foobar;');

A Function konstruktor meghívásakor az átadott paraméterek közül az utolsó lesz a függvény törzse, az előtt opcionálisan megadott paraméterek pedig a függvény paraméterei. Fontos megjegyezni, hogy a new kulcsszó megadása nem kötelező, nem befolyásolja a működést.

Miért nem ajánlott használni?

Mert a megadott függvény nem abban a környezetben fut le, ahol futtatjuk, hanem a globális névtérben, ezért hozzáférhet a globális névtérben megadott változókhoz, de azokhoz nem, ahol fut.

var foo = 10;
function bar() {
  var foo = 20,
      foobar = new Function('alert(foo);');

  foobar(); // 10;
}
bar();

return utasítás

Egy függvény visszatérhet futásának bármelyik pontján a return utasítás segítségével. Amennyiben nem adtunk meg visszatérési értéket (üres return utasítás), illetve a függvény legvégén nem adtunk ki return utasítást, akkor a függvény undefined értékkel tér vissza. A függvény visszatérhet akármilyen értékkel, legyen az valamilyen primitív típus, objektum, vagy akár egy függvény is.

function foo(bar) {
  if (bar === true)
    return 10;
  else if (bar === false) {
    return function () {
      return false;
    };
  }
  // implicit return undefined
}

Ha egy függvényt a new kulcsszóval hívunk meg (azaz konstruktorként), akkor a függvény – amennyiben nem adunk ki return utasítást –, akkor az aktuális this értékkel tér vissza; és amennyiben nem adunk át paramétereket, akkor a meghívásnál a zárójelek elhagyhatók.

function Foo() {
  // implicit return this
}

new Foo;

Closure (lexikai zárvány)

A függvények lehetővé teszik az úgynevezett lexikai zárvány használatát. A zárvány lényege, hogy hozzáférünk a függvényen kívüli változókhoz azután is, hogy a függvényen kívüli környezet már lefutott. Legegyszerűbben egy példával lehet bemutatni a működést.

function foo() {
  var bar = 'foobar';
  return function barfoo() {
    alert(bar);
  }
}

var foobar = foo();
foobar(); // 'foobar'

A fenti példában létrehoztunk egy foo() nevű függvényt, ami visszaad egy függvényt. A visszaadott barfoo() függvény – amit a foobar nevű változóban tároltunk el –, továbbra is hozzáfér a bar nevű változóhoz, holott a foo() függvény már régen lefutott. Lássuk a következő, igencsak klasszikus példát:

var foo = [], i, j;
for (i = 0; i < 5; i += 1) {
  // Függvényeket pakolunk bele a foo tömbbe.
  foo.push(function () { return i; });
}
for (j = foo.length - 1; j >= 0; j -= 1) {
  // Kiírjuk a konzolra a függvény futásának eredményét.
  console.log(foo[j]());
}

A fenti kis program 5 függvényt pakol bele a foo nevű tömbbe. A függvény visszaadja az i értékét. Ezután végigmegyünk fordított sorrendben a tömb elemein, és kiíratjuk a függvény futásának eredményét a konzolra. És egyesek meglepetésére minden esetben a konzolra az 5 íródik ki. Miért? Azért mert a függvényünk a zárványt használva hozzáfér az i értékéhez, és az első for ciklus futása után i értéke 5. Hogyan „javíthatjuk” meg a működést, azaz a függvényünk azt az értéket adja vissza, mint ami i volt a létrejöttekor?

var foo = [], i, j;
for (i = 0; i < 5; i += 1) {
  // Függvényeket pakolunk bele a foo tömbbe.
  foo.push(
    // IIFE-et hozunk létre, ami bezárja egy closure-be i értékét
    function (bar) {
      // Ezt a függvényt fogjuk ténylegesen bepakolni a tömbbe
      return function () {
        // a függvény a bar változót adja vissza, ami i akkori értéke
        return bar;
      }
    }(i)
  );
}
for (j = foo.length - 1; j >= 0; j -= 1) {
  // Kiírjuk a konzolra a függvény futásának eredményét.
  console.log(foo[j]());
}

Most már a foo tömbbe pakolt függvények hozzáférnek i eredeti értékéhez (bar-hoz), mivel azt egy closure-be zártuk. További információt az MDC Closures, illetve Dmitry A. Soshnikov Closures oldalain találunk.

this

A függvényeken belül a this értéke más nyelvekhez képest több dolgot jelenthet. Lássunk először is egy példát:

function foo() {
  console.log(String(this));
}
foo();
var bar = {
  foobar: foo
};
bar.foobar();

A fenti kódot böngészőben futtatva a következő kimenetet kapjuk:

[object Window]
[object Object]

Hogy is van ez? Alapvetően azok a függvények, amik nem egy objektum metódusai a window, vagy más környezetben, más globális névtér objektumot adnak vissza, this néven. Ilyen a foo() függvény is. Ugyanakkor, ha mint a bar objektum metódusaként hívjuk meg, akkor azt az objektumot veszik thisnek, aminek a metódusaként hívtuk meg (példánkban ez a bar). Most fordítsuk meg a fenti példát:

var bar = {
      foobar: function () {
        console.log(String(this));
      }
    },
    foo = bar.foobar;
foo();
bar.foobar();

A fenti leírás után remélhetőleg nem lepődik meg senki, hogy ugyanazt a kimenetet kapjuk, mint először. Az ok igencsak egyszerű. A foo() függvény ugyan a bar objektum egy metódusa, de nem, mint a bar objektum metódusa hívtuk meg, ezért a globális névtér objektum (a böngészőkben ez a window) lett a this.

call() és apply()

Minden függvény a JavaScriptben egyben objektum is, és van pár metódusa is. Ilyen metódus a call() és az apply(). Hogy ne legyen egyszerű az élet, a this értékét módosítani is tudjuk ezen metódusok használatával.

function foo(arg1, arg2) {
  console.log(String(this), arg1, arg2);
}
var bar = {};
foo.call(bar, "foobar", "barfoo"); // [object Object] foobar barfoo
foo.apply(bar, ["foobar", "barfoo"]); // [object Object] foobar barfoo

A függvények call() metódusa első paraméterként a thist várja, a többi paramétert pedig a függvény hagyományos paraméterként kapja meg. Az apply() metódus annyiban különbözik, hogy egy tömbszerű objektumot vár, mint második paraméter, és annak elemeit adja át a függvénynek paraméterként.

Amennyiben a call(), illetve apply() első paramétere null vagy undefined, akkor a this a globális névtér objektumra fog mutatni. Amennyiben valamilyen primitív érték (String, Number, Boolean), akkor az objektumként adódik át, mint this, azaz lefut rajta a megfelelő típus konstruktora.

var foo = [null, undefined, NaN, true, 0, 'string', [], {}],
    i, l;
function bar(arg) {
  console.log('this: ', String(this), typeof this, ' | arg: ', arg, typeof arg);
}
for (i = 0, l = foo.length; i < l; i += 1) {
  bar.call(foo[i], foo[i]);
}

Kimenetünk:

this: [object Window] object | arg: null object
this: [object Window] object | arg: undefined undefined
this: NaN object | arg: NaN number
this: true object | arg: true boolean
this: 0 object | arg: 0 number
this: string object | arg: string string
this: object | arg: [] object
this: [object Object] object | arg: Object {} object
strict mode

A strict mode használata jelentősen módosít ezen a működésen. Jelenleg strict mode használatára nem sok lehetőség van, de azért megemlítem, miben változnak a dolgok. A call(), illetve apply() nem módosítja az átadott paraméter típusát, azaz a null vagy undefined értéket első paraméterként átadva null, illetve undefined lesz a this értéke. Ehhez hasonlóan a primitív típusok se alakulnak át objektummá. Ennek megfelelően, amennyiben nem adtunk meg explicit this értéket a függvény meghívásakor, illetve nem egy objektum metódusaként hívjuk meg, akkor a this nem a globális objektum lesz, hanem undefined. További információt a strict mode működéséről az MDC illetve Dmitry A. Soshnikov oldalain találunk.

arguments objektum

Egy függvény argumentumaihoz a függvényen belül az arguments objektumon keresztül is hozzáférhetünk. Ez akkor hasznos, amikor változó számú paramétert vár a függvény, illetve ki akarjuk deríteni, hogy ténylegesen mennyi paramétert is adtak át neki a meghíváskor.

function foo() {
  console.log(arguments);
}
foo('bar', 'foobar'); // ["bar", "foobar"]

Ugyan az arguments objektum hasonlít egy tömbre, de sajnos(?) nem az. Rendelekezik egy length tulajdonsággal, valamint az egyes argumentumokhoz hozzáférhetünk a megfelelő indexek használatával, például az arguments[0] visszaadja az első paramétert, példánkban ez a bar. Ennek megfelelően egyszerűen végigmehetünk az összes argumentumon:

function foo() {
  var i, l = arguments.length;
  for (i = 0; i < l; i += 1) {
    alert(arguments[i]);
  }
}

Amennyiben az argumentumokat tömbként szeretnénk kezelni, egyszerűen átalakíthatjuk, így ezek után a tömb függvényeit már tudjuk használni:

function foo() {
  var args = Array.prototype.slice.call(arguments); // az args már egy tömb.
}

Ezen kívül az arguments objektum még rendelkezik két tulajdonsággal. Az arguments.callee egy hivatkozás az éppen futó függvényre, valamint az arguments.caller egy hivatkozás a függvényt meghívó függvényre. Ez utóbbi kettő használata kerülendő, ugyanis az arguments.caller már a JavaScript 1.3 óta elavult, az arguments.callee pedig nem használható strict mode esetén.

Magasabb rendű függvények

A magasabb rendű függvények (higher order function) olyan függvények, melyek más függvényekkel dolgoznak, azaz vagy paraméterként várják őket, vagy függvényeket adnak vissza.

Függvényt fogadó függvények

A ECMAScript 5 tömb metódusainak egy része egy függvényt vár paraméternek (map(), filter(), reduce(), reduceRight(), forEach(), every(), some()), de ilyen már régen a nyelv részét képező sort() is. Ezek jellemzően egy függvényt várnak első paraméternek, és a tömb elemein futtatják le ezt a függvényt. Például a tömb sort() metódusa egy opcionális függvényt vár paraméternek, ami pozitív, negatív, illetve 0 értékkel tér vissza, attól függően, hogy a két összehasonlított érték közül az elsőt nagyobbnak, kisebbnek illetve egyenlőnek tekintjük a másikkal. Például:

var array = [1, 2, 3];
// Rendezzük fordított sorrendben
array.sort(function (a, b) {
  if (a < b) {
    return 1;
  }
  else if (a > b) {
    return -1;
  }
  else {
    return 0;
  }
});
console.log(array); // [3, 2, 1]

Magunk is létrehozhatunk hasonló függvényeket:

function calculate(func, a, b) {
  return func(a, b);
}
function add(a, b) {
  returm a + b;
}
function multiply(a, b) {
  return a * b;
}
calculate(multiply, 5, 3); // 15
calculate(add, 5, 3); // 8

Amennyiben ECMAScript 5-öt nem ismerő környezetben akarunk végrehajtani a tömb összes elemén egy függvényt, akkor azt megtehetjük például a következőképpen:

function each(array, func) {
  var i, l = array.length;
  for (i = 0; i < l; i += 1) {
    func(array[i]);
  }
}
// Írjuk ki a tömb összes elemét, egyesével:
each([1, 2, 3], console.log);

Amennyiben a tömbből egy új tömböt akarunk generálni, használhatjuk például a map() függvényt:

function map(array, func) {
  var i, l = array.length, retArray = [];
  for (i = 0; i < l; i += 1) {
    // Minden elemre lefut a megkapott függvény,
    // aminek eredményével feltöltjük a tömböt.
    retArray[i] = func(array[i]);
  }
  return retArray;
}
map([1, 2, 3], function (a) { return a + 1 }); // [2, 3, 4]

A nyelvben persze más függvények is tekinthetők magasabb rendűnek, ugyanis például a setTimeout() és setInterval() is egy függvényt vár első paraméternek. A stringek replace() metódusa is opcionálisan tud függvényt fogadni második paraméterként.

Függvényt visszaadó függvények

Az is előfordulhat, hogy a függvény paramétereitől függően más függvényt szeretnénk használni, vagy generálni. Például több számhoz ugyanazt a számot szeretnénk hozzáadni, létrehozhatunk egy függvényt, ami ezt megteszi:

function addNumber(num) {
  return function (a) {
    // Closure miatt hozzáférünk a num változóhoz.
    return a + num;
  }
}
// az add10 függvény minden számhoz, amit paraméterként kap, 10-et ad hozzá.
var add10 = addNumber(10);
map([1, 2, 3], add10); // [11, 12, 13]
// Változó bevezetése nélkül, most 100-at adunk hozzá
map([1, 2, 3], addNumber(100)); // [101, 102, 103]

Magasabb rendű függvényekkel kapcsolatban érdemes elolvasni a következőket:

Összefoglalás

Mint láthattuk, a JavaScript nyelvben a függvények működése és használata igencsak összetett tud lenni. Éppen ezért minden esetben gondoljuk át, mikor, milyen formáját használjuk, valamint azt is, hogy milyen környezetben hozzuk létre. Talán kicsit sok is a buktató, viszont egy szépen felépített struktúra sokat tud hozzátenni az áttekinthetőséghez. Remélem ezzel a cikkel sikerült kicsit rendet tenni a fejekben, és többen elkezdenek elmerülni a JavaScript függvények szépségében. További olvasnivalót adhat a témában az MDC és Dmitry A. Soshnikov oldala.

 
Poetro arcképe
Poetro
1998 óta foglalkozik webfejlesztéssel, amikor is a HTML és a JavaScript világa elvarázsolta. Azóta jópár évet dolgozott reklámügynökségeknél, és nemzetközi hírportálok fejlesztésével. Legfőképpen Drupal fejlesztéssel, site buildinggel és JavaScripttel, azon belül is jQuery-vel és Node.js-sel foglalkozik.
1

Grat!

inf · 2011. Már. 30. (Sze), 09.15
Grat! Szerintem már nagyon nagy szükség volt egy ilyen cikkre! :-)
2

Szép munka!

Hidvégi Gábor · 2011. Már. 30. (Sze), 11.17
Szép munka!
3

Függvények

Hidvégi Gábor · 2011. Már. 30. (Sze), 11.34
Íme, az én módszereim függvényekre, hátha más is hasznát veszi, vagy tud jobbat ajánlani:

- nem szeretem az anoním függvényeket, mert hiba esetén a Firebug kb. ennyit ír rá: (?)(), inkább elnevezek mindent valahogy; tudom, kiírja a sor számát, de így már addig is tudok rajta gondolkozni, amíg megkeresem

- többször is előfordult már, hogy egy függvénynek sok paramétert kell átadni, mondjuk hatot, de néha csak az első hármat, néha csak az utolsó előtti kettőt, ami picit nehézkessé teszi a fejlesztést, mert utóbbi esetben meg kell adni az első három paraméter értékét, még ha az undefined is; emiatt én szinte csak objektumokat adok át paraméterként, aztán a függvényben megnézem, hogy mit van benne

- nemrég olvastam egy módszert, hogyan definiáljuk függvényünket úgy, hogy az Singletonként működjön, azaz ne lehessen többször példányosítani:

var Sarissa = new function Sarissa() {
  ...
}
4

Tetszett!

zzrek · 2011. Már. 30. (Sze), 17.29
Jó volt így magyarul olvasni, másoknak is ajánlani fogom.
Azon gondolkoztam el, hogy vajon miért csak a new kulcsszó esetén hagyható el a zárójel, ha nem adok át paramétert?
5

hívás vs érték

Poetro · 2011. Már. 30. (Sze), 17.49
Mert egyébként nem meghívod a függvényt, hanem mint kifejezés használod. Azaz
var x = new Foo,
    y = Foo;
Ugye ekkor y a Foo függvényre fog mutatni, azaz utána meg lehet hívni y()-ként.
7

És más kifejezésben?

zzrek · 2011. Már. 30. (Sze), 21.09
Igazad van, nekem csak azon járt az eszem, hogy nekem mi tetszene...
Pl. y=foo+2; Szerintem ilyenkor már egyértelmű, hogy meghívni akarom. Tetszene, ha pl. így lehetne használni: objektum.metodusamiobjektumotadvissza.tulajdonsag=20
8

És a metódus egy tulajdonsága?

Endyl · 2011. Már. 30. (Sze), 23.35
objektum.metodusamiobjektumotadvissza.tulajdonsag=20


Ebben az esetben hogyan érnéd el az objektumot visszaadó metódus egy tulajdonságát? (legyen az prototype vagy más -akár egyedileg definiált- tulajdonság)

Szerintem kár azon a két karakteren spórolni és csökkenteni a kód egyértelműségén. Erre ott vannak a kód miniatürizálók, meg a tömörítés is, ha a méret a lényeg.
9

Ez inkonzisztens

Török Gábor · 2011. Már. 31. (Cs), 07.11
Ez inkonzisztens viselkedéshez vezetne, ugyanis az általad felvetett y=foo+2 kifejezés nem identikus a y=foo()+2-vel.

function ketto() { return 2; }
ketto.toString = function() { return "kettő"; }
ketto() + 2; // 4
ketto + 2 // "kettő2"
10

Persze

zzrek · 2011. Már. 31. (Cs), 10.09
Persze, én nem akarom erőltetni ezt a dolgot, de azért szerintem több értelme van a zárójeltelen változatot hívásnak értelmezni, és azt amit most írsz, a gyakorlatban nemigazán használják, inkább erre kéne (kellett volna) valami jelölést kitalálni -- legalábbis talán nekem ez tetszett volna.
6

JSLint: Missing '()' invoking a constructor.

T.G · 2011. Már. 30. (Sze), 19.26
Csak egy nagyon apró kiegészítés.

function fn () {
    return 1;
}
var a = new fn();
console.log(a, typeof a, a instanceof fn);
Ha konstruktorként hívunk meg egy olyan függvényt, ami valamilyen primitív típusú értékkel térne vissza, akkor a visszatérési érték a megadottal értékkel szemben itt is a this lesz.

Ugyanebben a bekezdésben írtad, hogy a zárójel elhagyható, ha a paraméter lista üres lenne. Szerintem itt érdemes lenne megemlíteni, hogy ezt a JSLint nem szereti: Missing '()' invoking a constructor.
11

Nagyon

Ustak · 2011. Ápr. 2. (Szo), 10.39
tetszett!
Üdv:
Gábor
12

Bárhogy nézem nem tudok semmi

inf · 2011. Ápr. 2. (Szo), 11.57
Bárhogy nézem nem tudok semmi extrát hozzátenni, tényleg teljesen átfogó lett. :-)
13

Like!

Burnee · 2011. Ápr. 4. (H), 09.39
Hol lehet lájkolni? :)
14

Like alternatíva

Max Logan · 2011. Ápr. 4. (H), 11.33
Többször előkerült az utóbbi hónapokban a Like-olás kérdése. A magam részéről az egyszerű, Facebook like megoldást nem tartom jónak, főleg nem az ottani like gomb beépítését.

Ha már egyszer van egy ilyen egyedire alakított Drupal-unk és itt van minden kommentelőnek account-ja, akkor adja magát a megoldás a like-olásra.

Kellene csinálni egy olyan lehetőséget, hogy egy téma kedvencnek jelölhető. A DB-ből ki lehet olvasni, hogy hány embernél van kedvenc témának megjelölve. Ez is egy like megoldás és talán sokkal értelmesebb, mint a FB like; szerintem.

A kedvencnek jelölt topic-okat pedig lehetne minden user-nél listázni, így akár egymás adatlapján lehetne látni, hogy ki mi iránt érdeklődik, mely lehetőséget adna arra, hogy akár kisebb munkacsoportok alakuljanak a hasonló érdeklődésű tagok között, stb, stb.
15

Modul

Poetro · 2011. Ápr. 4. (H), 11.48
Ráadásul van rá rengeteg modul amit lehetne erre használni. Ilyen például a Flag, a Plus 1, a Vote Up/Down és a Rate. És ezek csak a legnépszerűbbek voltak. Már csak a vizuális beintegrálás a kérdés, de szerintem az se nagyobb munka.
16

Mindezek úgy volnának igazán

kuka · 2011. Ápr. 4. (H), 12.28
Mindezek úgy volnának igazán hasznosak már listázáskor, netalán keresés találatlistában látszana az értékelés. Ha már olvasom a témát, én is el tudom dönteni, hogy mennyire jó. A lényeg az volna, hogy még előtte megkapjam a többlet információt, hogy az értékesebb tartalmat részesíthessem előnyben.

Ezt támogassák az említett modulok?

Szerény véleményem szerint, bármi lehet, csak ne egy újabb nagytestvér aki figyeljen.
17

Légyszi az ilyen, Weblabort

Hidvégi Gábor · 2011. Ápr. 4. (H), 12.56
Légyszi az ilyen, Weblabort építő jellegű hozzászólásokat a már megnyitott fórumtémába írjátok, hogy egy helyen lehessen elérni mindet.
18

callee, caller

Hörb · 2011. Ápr. 6. (Sze), 12.45
Az arguments.callee és arguments.caller tulajdonságok helyett mit érdemes használni, ha erre lenne szükség?
19

A callee helyett miért kéne

inf · 2011. Ápr. 6. (Sze), 13.00
A callee helyett miért kéne mást használni?
(A caller meg ha jól tudom nem támogatott.)
20

... az arguments.callee pedig

Hörb · 2011. Ápr. 6. (Sze), 13.14
... az arguments.callee pedig nem használható strict mode esetén.


Csak ezért kérdeztem, gondoltam akkor van helyette valami jobb módszer ha az aktuális függvényre akarok hivatkozni.

De akkor a függvény belsejében nincs mód arra hogy kiderítsem melyik függvény hívta anélkül hogy paraméterként adnám át?
21

Hát hivatkozhatsz rá a

inf · 2011. Ápr. 6. (Sze), 13.25
Hát hivatkozhatsz rá a függvény saját nevével.

var i=0;
var f=function ()
{
	i+=1;
	if (i<10)
	{
		f();
	}
};
Szerintem nagyon ritkán kerül elő olyan formában, hogy arguments.callee.

Arra eddig sem volt mód, hogy kiderítsed, hogy mi hívta. A caller nem cross-browser tulajdonság. Egyébként meg ezek felesleges dolgok, mmint okés, hogy még rugalmasabbá lehet tenni egy kódot velük, de amúgy a gyakorlatban nem túl hasznosak.

Ami gyakorlati szempontból fontos az a függvényt visszaadó függvények, ezeknél meg nincs szükség az arguments.callee-ra. Debughoz meg van backtrace, meg ezer más dolog.
23

caller

Poetro · 2011. Ápr. 6. (Sze), 13.34
De akkor a függvény belsejében nincs mód arra hogy kiderítsem melyik függvény hívta anélkül hogy paraméterként adnám át?

Arra szolgált az arguments.caller.
24

Ha jól értem, akkor a strict

inf · 2011. Ápr. 6. (Sze), 15.45
Ha jól értem, akkor a strict módban cross-browser behozták az arguments.caller-t?
25

Nem

Poetro · 2011. Ápr. 6. (Sze), 16.18
Nem jól érted. Nincs se arguments.caller se arguments.callee. Ezért (is) érdemes kerülni a használatukat. Amennyiben valamiért mégis tudnia kell egy függvénynek egy másik függvényről, akkor azt kapja meg paraméterként.
26

Jó, akkor mégis jól tudtam.

inf · 2011. Ápr. 6. (Sze), 16.35
Jó, akkor mégis jól tudtam. :-)

Nekem az a tapasztalatom, hogy az arguments.callee és az arguments.caller teljesen feleslegesek. Az arguments meg simán lehetne tömb is objektum helyett (legalább nem kellene átkonvertálni a tömb metódusok használatához).

Ami nekem nagyon hiányzik ebből a nyelvből az az Object kulcsos Map. Ha lenne olyan Map, amiben a kulcsok DOM Node-k, akkor a jelenlegi gányolt böngészős megoldásokat lehetne egységesíteni egy node-k feletti felületben. Sajnos ilyen nincsen, és nem is lehet lérehozni (legalábbis msie-ben nem, a többi böngészőben igen). :S MSIE-vel az a legnagyobb para, hogy egyik DOM-al kapcsolatos objektum sem leszármazottja az Object-nek, és mivel nem Object-ek, ezért nem lehet property-ket lekérni vagy beállítani rajtuk.

szerk:
Tévedtem, még nagyon régi anyagaim között találtam egy htc-s megoldást, amivel az msie HTMLElement bővíthető. Ezzel már be lehet állítani a hashCode metódust a HTMLElement-re. Részben megoldható a probléma, viszont csak olyan elemekre használható, amiknek lehet style tulajdonsága.
36

Most fogalmam nincs, hogy

Karvaly84 · 2011. Dec. 31. (Szo), 00.43
Most fogalmam nincs, hogy keveredtem ide újra, de egyébként a JS Object-eket és DOM Node-okat a Chrome-ban és az Opera-ban lehet az elvárásoknak megfelelően manipulálni, kiterjeszteni az osztályokat, át írogatni úgy a metódusokat, hogy azok a prototípus láncban is benne legyenek. A MSIE kizárva! Főleg, hogy ott még Node sincs, és amit írsz a DOM Node-ok nem leszármazottjai az Object-nek. A Firefox az meg olyan, hogy a prototípus lánc-ba be tudsz írni új metódust, de ha felül írod mondjuk a HTMLElement.prototype.appendChild-et az nem öröklődik át a HTMLDivElement-re például, hanem továbbra is az eredetit használja. 3.6-ban próbáltam utoljára, aztán feladtam a harcot a nagy összevisszaságban.
37

MSIE-vel van olyan, hogy

inf · 2011. Dec. 31. (Szo), 05.05
MSIE-vel van olyan, hogy behavior meg htc fájl, abban be lehet állítani, hogy az Object.prototype-ból vegye át a módosításokat, ez viszont csak a HTML Element Node-okra vonatkozik, semmi többre, egyébként meg terheli a CPU-t, legalábbis azt mondják.
22

Leírtam

Poetro · 2011. Ápr. 6. (Sze), 13.29
Talán nem volt elég feltűnő, de azért szerepel a cikkben:
(function foo(bar) {  
  if (bar) {  
    foo(false);  
  }  
})('foobar'); 
A függvénykifejezés meghívja magát még egyszer (most már false paraméterrel), mivel tud saját magára hivatkozni a nevével.

Valamint az arguments.callee és arguments.caller használata nehezebbé teszik a JavaScript motorok belső optimalizálását. Legalábbis amit hallottam tesztek ezt bizonyítják.
28

fúbaz

demo · 2011. Ápr. 6. (Sze), 19.42
Köszi, jó összefoglaló. Személy szerint a sok foo meg baz között néha elvesztem. Esetleg egy-egy konkrétabb példán (könyvtáras, autós, akármi) keresztül levezetve még érthetőbb lenne.
29

Baris, kutyás?

Ustak · 2011. Ápr. 7. (Cs), 07.16
Ezt már elég régen írtam, de talán még aktuális. Vannak benne baris és kutyás példák pont ilyen esetekre :-)
js metaprogramozás
Üdv:
Gábor
30

wow

oroce · 2011. Ápr. 11. (H), 16.22
Huhh ez jó leírás volt :)
talán érdemes még megemlíteni a bind-ot, mert akkor ilyet is lehet írni:
var foo = [], i, j;  
for (i = 0; i < 5; i += 1) {  
  foo.push(  
    function (bar) {  
      return function () {  
        return bar;  
      }  
    }.bind(this,i) 
  );  
}  
for (j = foo.length - 1; j >= 0; j -= 1) {  

  console.log(foo[j]());  
}  
31

"Függvényt visszaadó

inf · 2011. Ápr. 11. (H), 16.35
"Függvényt visszaadó függvények"-hez tartozik. Ez már felhasználási mód, abból meg ezret lehetne írni...
32

Nem csak felhasználási mód

Endyl · 2011. Ápr. 11. (H), 18.11
33

Azt is szabványba tehetnék,

inf · 2011. Ápr. 11. (H), 20.17
Azt is szabványba tehetnék, hogy a DOM Node-k örököljék az Object.prototype-ot, mint minden más objektum.
34

arguments.caller

Karvaly84 · 2011. Jún. 24. (P), 12.24
Helló!

Lenne egy kérdésem: az arguments.caller helyett létezik valami alternatív megoldás? Írtad, hogy elavult. Esetleg lehet, hogy nem lesz mindig támogatott? Most jött az ötlet, hogy valami hibakereső rendszert lehetne írni a Function.prototype-ba amit pl egy try/catch blokkban elkapunk és vissza követünk, de ha nem tudok hivatkozni a függvényt meghívó függvényre akkor le is mondok róla. Ez csak minap jutott eszembe, és érdekelne valami szakvélemény.
35

Igen

Poetro · 2011. Jún. 24. (P), 13.48
Azt jelenti, hogy a JavaScript valamelyik következő változatában, esetleg valamelyik implementációjában már nem lesz támogatott. A böngészők illetve más JavaScript környezetek támogatják már most a visszakeresést, erre való a debugger kulcsszó, ami ekkor a debug rendszeren ki fogja írni hol tart a kód aktuális futása, valószínűleg teljes stack trace-szel (legalábbis a Firebug, a Chrome és a Safari fejlesztői eszköze ezt csinálja).