ugrás a tartalomhoz

Konstruktornak argumentumok átadása

Karvaly84 · 2011. Júl. 13. (Sze), 23.12
Helló guruk!

Kis segítség kéne a következőben: Van nekem egy konstruktor függvényem ami így fest:
  1. result = function() {  
  2.     var c = this;  
  3.     if (c.constructor != arguments.callee) {  
  4.         c = new arguments.callee();  
  5.     }  
  6.     return c.initialize.apply(c, arguments);     
  7. };  
A működés kb. annyi mint egyéb libekben, a konstruktor meghivja a initialize metódust aminek átadja az argumentumokat. A kódot úgy szerveztem hogy ne keljen a new szóval kezdeni a példányosítást, és a probléma evvel függ össze: amikor a feltételben példányosítom az argument.callee függvényt hogy a this a helyén legyen, ott van mód arra hogy argumentumokat adjak át valahogy az arguments tömbből? Jelenleg az a problémám, hogy így kétszer fut le az initialize.
 
1

Problémák

Poetro · 2011. Júl. 13. (Sze), 23.51
Eleve nem illik arguments.callee-t használni, inkább adj nevet a függvényednek. Másodsorban mivel a new-nak nem lehet átadni tudtommal változó paramétereket, ezért meggondolnám eleve, hogy jó ötlet-e. Másik dolog, ha valami egy konstruktor, akkor nagy betűvel kezdjük, ha nem az, akkor meg kicsivel.
  1. Result = function Entity(args) {  
  2.   var that = this;  
  3.   if (!(that instanceof Entity)) {  
  4.     return new Entity(args);  
  5.   }  
  6.   that.init.apply(that, args);  
  7.   return that;  
  8. }  
  9. Result.prototype.init = function () {  
  10. };  
  11. new Result([1, 2, 3]);  
  12. Result([1, 2, 3]);  
Az initialize azért fut le kétszer, mert ha nem Entity típusú a this, akkor létrehozol egy új elemet (ami meg fogja hívni az initialize-t), majd, mivel nem tértél vissza az eredeti függvényből, újból meg lesz hívva.

Másik megközelítés lehet, hogy teljes mértékben elfelejted a new operátort, és helyette az Object.create szintaxist használod.
  1. function Entity() {  
  2.   var that = this;  
  3.   if (!(that instanceof Entity)) {  
  4.     that = Object.create(Entity.prototype);  
  5.     console.log('Object created');  
  6.   }  
  7.   that.init.apply(that, arguments);  
  8.   return that;  
  9. }  
  10. Entity.prototype.init = function () {  
  11.   console.log('Object initialized');  
  12. };  
  13.   
  14. new Entity(1, 2, 3));  
  15. Entity(1, 2, 3);  
2

Tudom, hogy nem illik majd

Karvaly84 · 2011. Júl. 14. (Cs), 02.05
Tudom, hogy nem illik majd változtatok ezen. A konstruktor azért van kisbetűvel írva mert a result egy összetett függvénynek az eredménye amit a végén vissza küldök és kötök egy változóhoz ami már terméseztessen nagy betűvel kezdődik. Nem másoltam be az egész kódot, a lényeg van egy függvényem ami kap változó hosszúságú paramétert, át konvertálom a arguments tömböt Array típusú tömbbé. De inkább mutatom:
  1. var args = slice(arguments), result, pack, ns, name, type, ext, k, i;  
  2.     pack = typeof args[0] == 'string' ? args.shift() : null;  
  3.     type = args.pop() || {};  
Szóval itt egy kicsit összetettebb téma, az alap ötlet a prototype.js-ből jött de ott a konstruktor nem tér vissza értékkel, én pedig azt szeretném elérni hogy akár egy null-t is vissza tudjon adni annak ellenére hogy new operátor használva van.

Úgy tudom (de javíts ki ha nem jól), hogy a Object.create az EcmaScript 5-től elérhető, bár az ötlet jó, lehet egy sima prototype másolás is megteszi ezt most mindjárt ki próbálom köszi.

folyt.: végül ezt csináltam:
  1. result = function() {  
  2.     var c = this;  
  3.     if (c.constructor != arguments.callee) {  
  4.         c = function() {};  
  5.         c.prototype = arguments.callee.prototype;  
  6.         c = new c();  
  7.     }  
  8.     return c.initialize.apply(c, arguments);     
  9. };  
Bár ez kicsit biztos lassít probléma ez így?
3

Kész megrogytam!

Karvaly84 · 2011. Júl. 14. (Cs), 05.30
Ennek a konstruktornak azt kéne csinálnia, hogy vissza adja számként, mennyi argumentumot kapott. Tudom, hogy egy konstruktor nem erre való, de ha a new operátort használva egy konstruktor vissza tér valamilyen értékkel akkor kifejezés értéke az lesz nem pedig egy új objektum. Nekem a two változó nem egy szám hanem a Class egy példánya. Mit nem veszek észre?
  1. function Class() {  
  2.     var instance = this;  
  3.     if (instance.constructor !== Class) {  
  4.         function Constructor() {};  
  5.         Constructor.prototype = Class.prototype;  
  6.         instance = new Constructor();  
  7.     }  
  8.     return instance.initialize.apply(instance, arguments);  
  9. }  
  10.   
  11. Class.prototype = {  
  12.         constructor : Class,  
  13.     initialize : function() {  
  14.         return arguments.length;  
  15.     }  
  16. };  
  17.   
  18. var one = new Class('arg');  
  19. var two = Class('arg''arg');  
  20.   
  21. console.log('one: ' + one + '\ntwo: ' + two);  
4

Én azt nem értem, hogy mit nem értesz. :)

T.G · 2011. Júl. 14. (Cs), 07.40
Én azt nem értem, hogy mit nem értesz. :)

Egy new operátor nem fog számot visszaadni, akárhogy csavarod, akkor sem. Tehát az első esetben hiába van a 8. sorban egy szám visszatérő érték, az felül lesz írva, mivel primitív értékkel térne vissza.
Lecserélheted azt a sort az alábbi verzióra:
  1. return [instance.initialize.apply(instance, arguments)];  
Így már nem primitív, azaz ezt fogja visszaadni.

Bár megjegyzem, hogy nagyon rossz irány az, hogy a new operátort opcionálissá teszed. De ez csak az én személyes véleményem. :)
6

Köszönöm, ez az amit nem

Karvaly84 · 2011. Júl. 14. (Cs), 14.38
Köszönöm, ez az amit nem tudtam, hogy primitív értékkel nem tud vissza térni. :)
5

instanceof

Poetro · 2011. Júl. 14. (Cs), 12.12
Mi a bajod az instanceof operátorral, miért nem használod az Object.create-et?
  1. if (!Object.create) {  
  2.     Object.create = function (o) {  
  3.         if (arguments.length > 1) {  
  4.             throw new Error('Object.create implementation only accepts the first parameter.');  
  5.         }  
  6.         function F() {}  
  7.         F.prototype = o;  
  8.         return new F();  
  9.     };  
  10. }  
Így könnyebb lesz majd az átállás ECMAScript 5-re (arról nem is beszélve, hogy a böngészők natív implementációja jóval gyorsabb, és minden új böngésző támogatja már).

Ha new operátorral hívsz meg egy függvényt, akkor az mindenképpen egy objektumot fog visszaadni, és a primitív szám nem objektum, maximum ha belecsomagolod egy Number-be (return new Number(arguments.length)).
7

Az Object.create szintaxis-t

Karvaly84 · 2011. Júl. 14. (Cs), 15.17
Az Object.create szintaxis-t azért nem használom mert IE nem szereti az újításokat, és ez 6-7-8-ban nem működne, bár kb ugyan ezt csináltam amit most te, az instanceof operátorral meg az a bajom hogy ha a this véletlenül nem a közvetlen példánya a Class osztálynak hanem mondjuk annak kiterjesztésének példánya akkor az gubanc.
Ha new operátorral hívsz meg egy függvényt, akkor az mindenképpen egy objektumot fog visszaadni, és a primitív szám nem objektum, maximum ha belecsomagolod egy Number-be (return new Number(arguments.length)).
Ez jó tipp köszönöm!
8

Jól működik

Poetro · 2011. Júl. 14. (Cs), 18.34
Az Object.create jól működik IE alatt is, habár csak 7-8-9-ben próbáltam. Az instanceof pedig a leszármazottakra is igazat ad vissza (IE-ben is.)