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:

result = function() {
    var c = this;
    if (c.constructor != arguments.callee) {
        c = new arguments.callee();
    }
    return c.initialize.apply(c, arguments);   
};
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.

Result = function Entity(args) {
  var that = this;
  if (!(that instanceof Entity)) {
    return new Entity(args);
  }
  that.init.apply(that, args);
  return that;
}
Result.prototype.init = function () {
};
new Result([1, 2, 3]);
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.
function Entity() {
  var that = this;
  if (!(that instanceof Entity)) {
    that = Object.create(Entity.prototype);
    console.log('Object created');
  }
  that.init.apply(that, arguments);
  return that;
}
Entity.prototype.init = function () {
  console.log('Object initialized');
};

new Entity(1, 2, 3));
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:

var args = slice(arguments), result, pack, ns, name, type, ext, k, i;
    pack = typeof args[0] == 'string' ? args.shift() : null;
    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:

result = function() {
    var c = this;
    if (c.constructor != arguments.callee) {
        c = function() {};
        c.prototype = arguments.callee.prototype;
        c = new c();
    }
    return c.initialize.apply(c, arguments);   
};
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?

function Class() {
	var instance = this;
	if (instance.constructor !== Class) {
		function Constructor() {};
		Constructor.prototype = Class.prototype;
		instance = new Constructor();
	}
	return instance.initialize.apply(instance, arguments);
}

Class.prototype = {
        constructor : Class,
	initialize : function() {
		return arguments.length;
	}
};

var one = new Class('arg');
var two = Class('arg', 'arg');

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:
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?
if (!Object.create) {
    Object.create = function (o) {
        if (arguments.length > 1) {
            throw new Error('Object.create implementation only accepts the first parameter.');
        }
        function F() {}
        F.prototype = o;
        return new F();
    };
}
Í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.)