Toon posts:

[js] dynamisch functies toevoegen

Pagina: 1
Acties:

Verwijderd

Topicstarter
Ik ben bezig met het maken van een SOAP client in javascript (die ik een beetje crossbrowser kan inzetten). Nu lees ik een WSDL file in en haal daaruit de functienamen en parameters van de SOAP server. Dat gaat prima allemaal (als je het niet volgt, maakt niet uit, ik heb een lijstje functienamen en paramaters beschikbaar)

Wat ik nu eigenlijk wil, is functies aan m'n client toevoegen zodat ik ze kan aanroepen als ware het locale functies, dus stel ik heb een functienaam "doSomething", dan wil ik een method in m'n client aanmaken zodat ik soapClient.doSomething() kan zeggen en de boel dus een request gaat doen naar de soapserver en een waarde retourneerd (synchroon nog even).

wat ik dus tot nu toe in elkaar heb zitten:
code:
1
2
3
4
5
6
soapServer.prototype.loadFunctions = function() {
    for (var i=0; i<this.functions.length; i++) {
        var funcName = this.functions[i];
        this[funcName] = new Function(function() {"alert(arguments)")
    }
}

dat werkt, ik maak nieuwe methods aan op deze manier, maar ik wil meer :P
ik wil natuurlijk niet de arguments alerten, maar in elkaar klussen tot een xml string voor de soap request. Tijdens dat klussen heb ik ook de naam van de functie zelf nodig. En dan wordt het lastig, want iets als
code:
1
this[funcName] = new Function(function() {"alert(funcName)")

gaat natuurlijk niet werken, want die funcName zit niet binnen de scope van die functie

het mooiste zou zijn als ik vanuit deze nieuwe functie een standaard method van m'n object kan aanroepen, bijvoorbeeld deze:
code:
1
2
3
soapClient.prototype.execute = function(funcName, args) {
//produceer een soap request de functienaam en argumenten
}


offtopic:
hoop dat er een keer iemand op m'n topics reageert :P

[ Voor 4% gewijzigd door Verwijderd op 16-02-2006 21:55 ]


  • X-Lars
  • Registratie: Januari 2004
  • Niet online

X-Lars

Just GoT it.


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

call/apply? of mis ik hier iets?

edit: naam van de functie waar je in zit kan je wel uit arguments.callee klussen, of zoiets doen:
JavaScript:
1
2
3
4
5
6
7
function thisIsMyFunction()
{
    alert(arguments.callee.name);
}

thisIsMyFunction.name = 'thisIsMyFunction';
thisIsMyFunction();

:)

[ Voor 150% gewijzigd door crisp op 16-02-2006 23:11 ]

Intentionally left blank


  • SuperRembo
  • Registratie: Juni 2000
  • Laatst online: 20-08-2025
Verwijderd schreef op donderdag 16 februari 2006 @ 20:29:
want iets als
code:
1
this[funcName] = new Function(function() {"alert(funcName)")

gaat natuurlijk niet werken, want die funcName zit niet binnen de scope van die functie
Zoiets als dit werkt wel
code:
1
2
3
4
5
6
7
var f = [];
for (var i = 0; i < 3; i++) {
    f[i] = function(){alert(i)};
}
for (var i = 0; i < 3; i++) {
    f[i]();
}


Kijk eens naar [google=javascript closures], of het timer voorbeeld in de link hierboven.

| Toen / Nu


  • Amras
  • Registratie: Januari 2003
  • Laatst online: 01-10-2025
Ik snap nog niet helemaal wat je bedoelt, maar je zou toch gewoon een property name aan een Function object kunnen toevoegen? Niet heel mooi misschien, maar dan krijg je dit:
JavaScript:
1
2
this[funcName] = new Function(function() {"alert(arguments)");
this[funcName].name = funcName;


Je zou het ook zoals crips via de callee property kunnen oplossen, ook niet heel mooi maar werkt ook prima.

  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Nee, dat werkt niet:
JavaScript:
1
2
3
4
5
6
7
8
var f = [];
for (var i = 0; i < 3; i++) {
    f[i] = function(){alert(i)};
}

f[0](); // 3
f[1](); // 3
f[2](); // 3

;)

Intentionally left blank


  • SuperRembo
  • Registratie: Juni 2000
  • Laatst online: 20-08-2025
Ja, ik merk het. Het leek alleen goed te gaan doordat het tweede loopje ook i gebruikte |:(

[ Voor 5% gewijzigd door SuperRembo op 16-02-2006 23:18 ]

| Toen / Nu


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

SuperRembo schreef op donderdag 16 februari 2006 @ 23:18:
[...]


Ja, ik merk het. Het leek alleen goed te gaan doordat het tweede loopje ook i gebruikte |:(
Dit werkt wel:
JavaScript:
1
2
3
4
5
6
7
8
9
10
11
var f = {};
f.function1 = createFunction('function1');
f.function2 = createFunction('function2');

function createFunction(name)
{
    return function() { alert(name); }
}

f.function1();
f.function2();

:)
Amras schreef op donderdag 16 februari 2006 @ 23:14:
Ik snap nog niet helemaal wat je bedoelt, maar je zou toch gewoon een property name aan een Function object kunnen toevoegen? Niet heel mooi misschien, maar dan krijg je dit:
JavaScript:
1
2
this[funcName] = new Function(function() {"alert(arguments)");
this[funcName].name = funcName;


Je zou het ook zoals crips via de callee property kunnen oplossen, ook niet heel mooi maar werkt ook prima.
Hoe kom je in jouw voorbeeld dan binnen je gecreëerde functie aan de name property zonder de callee property te gebruiken? 'this' verwijst echt niet naar je functie-object hoor ;)

[ Voor 44% gewijzigd door crisp op 16-02-2006 23:21 ]

Intentionally left blank


  • Amras
  • Registratie: Januari 2003
  • Laatst online: 01-10-2025
crisp schreef op donderdag 16 februari 2006 @ 23:19:
Hoe kom je in jouw voorbeeld dan binnen je gecreëerde functie aan de name property zonder de callee property te gebruiken? 'this' verwijst echt niet naar je functie-object hoor ;)
Niet, ik had er even niet bij stil gestaan dat je ook gewoon de callee property nodig hebt om een referentie naar je function te krijgen. ;)

Verwijderd

Topicstarter
callee is wel een aardige, maar dit:
code:
1
2
3
4
for (var i=0; i<this.functions.length; i++) {
   var funcName = this.functions[i];
   this[funcName] = new Function(function() {"alert(arguments.callee.name)")
}

levert "anonymous" op

/me klust nog even verder

edit:
tweede voorbeeld van crisp lijkt wel te gaan werken, is me alleen nog niet helemaal duidelijk waarom nu eigenlijk

[ Voor 25% gewijzigd door Verwijderd op 17-02-2006 07:47 ]


  • crisp
  • Registratie: Februari 2000
  • Nu online

crisp

Devver

Pixelated

Het verschilt natuurlijk of je de function constructor gebruikt wat een reference naar een anonymous function teruggeeft, of met het function statement direct een functie-object aanmaakt en toekent aan een variabele.
Bij het gebruik van de constructor kan je natuurlijk gewoon dit doen:
JavaScript:
1
this[funcName] = new Function("alert('"+funcName+"')");

Jouw manier om de function constructor te gebruiken komt een beetje vreemd op me over. In plaats van een string als functie-body gebruik jij een function statement. Die zal dus eerst omgezet gaan worden naar een string-variant en dan door de constructor gehaald worden. Dit:
JavaScript:
1
this[funcName] = new Function(function() {"alert(arguments.callee.name)"})

levert een anonymous function op, met daarbinnen een functie die niets doet (want wordt ook niet uitgevoerd en bevat sowieso geen statements, enkel de string "alert(arguments.callee.name)" die niet eens ergens aan assigned wordt).
En dit:
JavaScript:
1
this[funcName] = new Function("alert(arguments.callee.name)")

levert inderdaad 'anonymous' op.

Het 2e voorbeeld is gewoon een closure; de variabele 'name' is bekend binnen de scope van createFunction en derhalve ook binnen de functie die in createFunction gedefinieerd is. Aangezien deze functie geretourneerd wordt blijft de scope-chain bewaard en blijft ook de referentie naar 'name' binnen de scope van createFunction bewaard.

[ Voor 72% gewijzigd door crisp op 17-02-2006 08:56 ]

Intentionally left blank


Verwijderd

Topicstarter
volgens mij heb ik ergens een copy paste fout gemaakt in m'n vorige post, want volgens mij had ik je laatste variant gedaan.

wat ik nu dus heb (en wat werkt in fx, voor IE moet ik nog even de boel aanpassen ivm dingen als array.push() en getELementsByTagNameNS()

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
soapClient.prototype.loadFunctions = function() {
    this.server = this.WSDLDOM.getElementsByTagName('service')[0].getElementsByTagNameNS('http://schemas.xmlsoap.org/wsdl/soap/','address')[0].getAttribute('location');
    this.ops = this.WSDLDOM.getElementsByTagName('portType')[0].getElementsByTagNameNS('http://schemas.xmlsoap.org/wsdl/','operation');
    for (var i=0; i<this.ops.length; i++) {
        var funcName = this.ops[i].getAttribute('name');
        this.functions.push(funcName);
        this[funcName] = this.createRemoteOperation(funcName);
    }
}

soapClient.prototype.createRemoteOperation = function(fname) {
    return function() {
        var req = '<?xml version="1.0"?>\n<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">\n<soap:Body>\n';
        req += '<m:'+fname+' xmlns:m="http://www.rikkertkoppes.com/tests/soap">\n';
        for (var i=0; i<arguments.length; i++) {
            req += '<input>'+arguments[i]+'</input>\n';
        }
        req += '</m:'+fname+'>\n';
        req += '</soap:Body>\n</soap:Envelope>\n';
        alert(this.request(this.server,req,false,'POST').responseText);
    }
}
Pagina: 1