Toon posts:

String naar function

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik zit met iets waar ik even niet weet hoe het aan te pakken. Ik heb in een xml file als attribute van een node een verwijzing naar een function. Deze node wordt geparsed naar een div element, en zodra dit afgerond is wordt de gespecificeerde functie afgevuurd.

Waar ik vast loop, is dat zodra ik de functie vanuit xml lees, hij ook als string terugkomt, logisch. Maar daarna kan ik geen enkele wijze vinden om dit te converteren naar een function die ook daadwerkelijk wat gaat doen.

Als ik de function (eerste commented regel met var test) handmatig code, gaat het perfect, de method wordt uitgevoerd. Zodra het uit xml komt kan ik het casten naar een function, evaluaten, enzovoorts, maar de function wordt niet uitgevoerd ondanks dat een typeof wel aangeeft dat de waarde test een function is.

Ik kan nog een apply proberen, maar iemand nog suggesties?

<node onloadevent="this.test()" />
code:
1
2
3
4
5
6
function foo(){
this.onloadevent = oNode.getAttribute("onloadevent");
this.eventManager = new EventManager();
}

foo.prototype.test = function(){alert('test');}


Voorheen werd dit afgevuurd door this.onloadevent() aan te roepen, maar ik heb dit gerefactored met een eventmanager zodat het onloadevent wordt getriggered als aan een bepaalde conditie is voldaan.

Dit was dus voorheen, en dit werkte wel (waar het nog werd aangeroepen als onderdeel van een member van de class foo).
code:
1
2
3
foo.prototype.whenready = function(){
  this.onloadevent();
}

code:
1
2
3
4
5
6
7
8
9
var self = this;
//var test = function(){this.test()};
//var test = this.onloadevent;
//var test = function(){this.onloadevent};
//var test = function(){this.onloadevent()};
//var test = function(){eval(this.onloadevent)};
//var test = function(){self.onloadevent()};

this.eventManager.addListener("whenready",test);


Event manager
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
function EventManager(){
    this.types = new Array();
}
EventManager.prototype.addListener = function(type,action,args){
    if(this.types[type] == null){
        this.types[type] = new EventQueue();
    }
    this.types[type].add(action,args);
}
EventManager.prototype.dispatch = function(type){
    if(this.types[type] != null){
        var eventQueue = this.types[type];
        var events = eventQueue.getEvents();
        for(var i=0,j=eventQueue.getLength();i<j;i++){
          //events[i].action;
           //new function(){events[i].action}
           //eval(events[i].action);
           events[i].action();
        }
    }
}

function EventQueue(){
    this.events = new Array();
}
EventQueue.prototype.add = function(action,args){
    this.events.push({action:action,args:args});
}
EventQueue.prototype.getEvents = function(){
    return this.events;
}
EventQueue.prototype.getLength = function(){
    return this.getEvents().length;
}

[ Voor 25% gewijzigd door Verwijderd op 01-11-2006 22:27 ]


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:31

crisp

Devver

Pixelated

daar is de Function constructor toch voor?
JavaScript:
1
2
3
4
5
6
7
function foo()
{
    var self = this;
    this.onloadevent = new Function(oNode.getAttribute('onloadevent'));
    this.eventManager = new EventManager();
    this.eventManager.addListener('whenready', function(){self.onloadevent()});
}

Intentionally left blank


Verwijderd

Topicstarter
Juistem, dat dacht ik dus ook (zie oa de lijst met comments). Maar zowel FF2, als IE6/IE7 gaan er niet mee akkoord. Je krijgt geen meldingen van errors, maar uiteindelijk wordt de functie niet getriggered.

Ik kan anders wel even een testcase online zetten, dan hebben we een demo om de wazigheid aan te tonen. :)

[ Voor 21% gewijzigd door Verwijderd op 02-11-2006 09:04 ]


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Wat voor output zie je als je alert(events[i].action) in je dispatch functie doet?

Verder zou het idd. wel handig zijn, zo'n testcase, als je er niet uitkomt.

Noushka's Magnificent Dream | Unity


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:31

crisp

Devver

Pixelated

Verwijderd schreef op donderdag 02 november 2006 @ 09:02:
Juistem, dat dacht ik dus ook (zie oa de lijst met comments). Maar zowel FF2, als IE6/IE7 gaan er niet mee akkoord. Je krijgt geen meldingen van errors, maar uiteindelijk wordt de functie niet getriggered.
uh, nee :? Ik zie je in je comments alleen maar gebruik maken van een function literal...
Het voorbeeldje wat ik hierboven postte werkt, hoewel je nog steeds wel een closure nodig hebt om de scope goed te krijgen.
Ik kan anders wel even een testcase online zetten, dan hebben we een demo om de wazigheid aan te tonen. :)
Kleine (niet-)werkende testcase zou inderdaad wel handig zijn :)

Intentionally left blank


Verwijderd

Topicstarter
Indien je het event als function(){} meegeeft is typeof van het type function, en geeft de alert ook daadwerkelijk de inhoud van de function terug. Het enige wat er niet gebeurd, is dat deze ook daadwerkelijk wordt uitgevoerd.

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:31

crisp

Devver

Pixelated

Verwijderd schreef op donderdag 02 november 2006 @ 09:25:
Indien je het event als function(){} meegeeft is typeof van het type function, en geeft de alert ook daadwerkelijk de inhoud van de function terug.
Het enige wat er niet gebeurd, is dat deze ook daadwerkelijk wordt uitgevoerd.
Ja, natuurlijk, als je iets wrapped in een function literal dan heb je ook een anonymous function. Punt is echter dat je in dit geval enkel een string erin wrapped; feitelijk krijg je dus dit:
JavaScript:
1
function() { 'this.test();'; }

Syntactisch niets mis mee, alleen gebeurd er niet veel als je dat uitvoerd :)
Daarom moet je ook de Function constructor gebruiken:
JavaScript:
1
new Function('this.test();');

Intentionally left blank


Verwijderd

Topicstarter
Ik zal vanavond eens een demo in elkaar zetten. Wie weet ben ik gewoon achtelijk bezig en doe ik het inderdaad niet goed, en anders komt de demo online. :) Ik kan me haast niet voorstellen dat ik een fout had gemaakt, want ik had inderdaad ook al getest door middel van new Function, maar wellicht niet goed.

Verwijderd

Topicstarter
Ik heb een demo in elkaar gezet. Specifiek waar het om gaat, is de nodeAttribute variant die wordt voorzien van een string (functie in de node attribute van een xml node).

Volgens mij mis ik gewoon iets heel simpels:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
<script type="text/javascript">
function foo(){
    var self = this;
    this.eventManager = new EventManager();
    
    var xmlString = "self.test('a');"
    var nodeAttribute = new Function(xmlString);
    var hardCoded = function(){self.test('b')};

    this.eventManager.addListener("klik",nodeAttribute);
    this.eventManager.addListener("klik",hardCoded);
}

foo.prototype.afvuren = function(){
    this.eventManager.dispatch('klik');
}
foo.prototype.test = function(type){
    alert('test:'+type);
}


function EventManager(){
    this.types = new Array();
}
EventManager.prototype.addListener = function(type,action,args){
    if(this.types[type] == null){
        this.types[type] = new EventQueue();
    }
    this.types[type].add(action,args);
}

function EventQueue(){
    this.events = new Array();
}
EventQueue.prototype.add = function(action,args){
    this.events.push({action:action,args:args});
}
EventQueue.prototype.getEvents = function(){
    return this.events;
}
EventQueue.prototype.getLength = function(){
    return this.getEvents().length;
}
EventManager.prototype.dispatch = function(type){
    if(this.types[type] != null){
        var eventQueue = this.types[type];
        var events = eventQueue.getEvents();
        for(var i=0,j=eventQueue.getLength();i<j;i++){
            events[i].action();
        }
    }
}

var testClass = new foo();
testClass.afvuren();
</script>

  • user109731
  • Registratie: Maart 2004
  • Niet online
Mja, zoiets werkt wel:

JavaScript:
1
var nodeAttribute = function() { new Function('self', xmlString)(self) };

Ziet er niet erg elegant uit... Maar je geeft je nieuwe functie zeg maar een extra argument mee, die dus ook self heet... :)

Nogmaals, ik vind het zelf ook niet echt netjes, maar als er geen beter alternatief is...

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:31

crisp

Devver

Pixelated

maak van
JavaScript:
1
var xmlString = "self.test('a');"

eens
JavaScript:
1
var xmlString = "this.test('a');"

Intentionally left blank


Verwijderd

Topicstarter
Crisp, dan krijg je van de debugger de melding "this.test() is not a function".
Geef helaas ook geen resultaat.

In feite zou je de functie ook niet hoeven te scopen maar het was even geplaatst om alle variabelen uit de weg te ruimen wat betreft problemen.

  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:31

crisp

Devver

Pixelated

Je voorbeeld week toch nog af tov mijn voorbeeld mbt het expliciet scopen; dit werkt:
JavaScript:
1
2
3
4
5
6
7
8
9
10
function foo()
{
    var self = this;
    this.eventManager = new EventManager();
    
    var xmlString = "this.test('a');"
    var nodeAttribute = function(){new Function(xmlString).call(self);};

    this.eventManager.addListener("klik", nodeAttribute);
}

Intentionally left blank


Verwijderd

Topicstarter
wtf .. function(){new Function()} :? Een vreemde constructie maar het werkt nu inderdaad perfect. 8)7

Ik kan er echter niet tegen als ik niet volg wat er hier nu gebeurt. new Function definieert de string als een functie, call past de scope inderdaad toe. Maar waarom nog een function eromheen? ..

[ Voor 91% gewijzigd door Verwijderd op 03-11-2006 10:22 ]


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Kleine wijziging:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
function foo() 
{ 
    var self = this; 
    this.eventManager = new EventManager(); 
     
    var xmlString = "this.test('a');";
    var event = new Function(xmlString);
    var nodeAttribute = function(){event.call(self);}; 

    this.eventManager.addListener("klik", nodeAttribute); 
}

Zo wordt tenminste niet iedere keer een nieuw functie object gemaakt.

Die wrapper moet, omdat de gemaakte functie in de context van het huidige object moet worden aangeroepen. Als je puur een referentie naar de functie direct geeft, dan wordt hij niet in de context van het huidige object aanroepen, en dan verwijst this dus niet naar het huidige object (maar naar window dacht ik).

Noushka's Magnificent Dream | Unity


  • crisp
  • Registratie: Februari 2000
  • Laatst online: 00:31

crisp

Devver

Pixelated

En als je event nu een property maakt van het object dan hoef je helemaal niet meer met call of apply te werken en krijg je weer mijn eerste voorbeeld ;)

Intentionally left blank


  • Michali
  • Registratie: Juli 2002
  • Laatst online: 09-12-2025
Idd. Wat kan een beetje refactoren toch verhelderend werken :P

Noushka's Magnificent Dream | Unity

Pagina: 1