2010-06-22 11 views
7

Ok, sono un po 'perplesso. Probabilmente mi manca qualcosa di evidentemente evidente ma a quanto pare non riesco a vedere la foresta per gli alberi:Come creare un array JavaScript "reale" in Rhino

Sto provando a chiamare una funzione JavaScript che si aspetta che il suo parametro sia una matrice, cioè controlla if (arg instanceof Array)... Purtroppo, I (o Rhino) proprio non riesco a creare una tale varietà:

Context cx = Context.enter(); 
    Scriptable scope = cx.initStandardObjects(); 
    String src = "function f(a) { return a instanceof Array; };"; 

    cx.evaluateString(scope, src, "<src>", 0, null); 

    Function f = (Function) scope.get("f", scope); 
    Object[] fArgs = new Object[]{ new NativeArray(0) }; 
    Object result = f.call(cx, scope, scope, fArgs); 

    System.out.println(Context.toString(result)); 

    Context.exit(); 

e, ahimè, è resultfalse.

Cosa mi manca qui?

Edit:
Solo un po 'più di informazioni: sia [] instanceof Array e new Array() instanceof Array ritorno true come ci si aspetterebbe. Se aggiungo elementi all'array fanno vedere nel codice JavaScript con gli indici di destra (numerici, partendo da zero):

NativeArray a = new NativeArray(new Object[]{ 42, "foo" }); 

Quando output utilizzando questa funzione JavaScript:

function f(a) { 
     var result = []; 
     result.push(typeof a); 
     for (var i in a) { 
      result.push(i + ' => ' + a[i]); 
     } 
     return result.join('\\n'); 
    } 

Il risultato è :

object 
    0 => 42 
    1 => foo 

Quindi funziona. Solo che io voglio un array di 'reale' :)

+1

Potrebbe aggiungere alcuni diagnistics a f() per scoprire quale sia l'argomento che ottieni in realtà? – djna

+0

Ho aggiunto alcune informazioni, forse questo aiuta – n3rd

+1

Il controllo che la libreria sta facendo ('a instanceof Array') è ragionevole, ma limitato. Ad esempio, anche senza Rhino, non sarebbe in grado di identificare una matrice in un'applicazione basata su browser se quell'array proveniva da un'altra finestra. Proverai ad aggiungere 'result.push (Object.prototype.toString.call (a));' alla tua funzione? Sarà interessante vedere se dice '[oggetto oggetto]' o '[oggetto Matrice]'. Quest'ultimo sarebbe simile a un array di un'altra finestra, il primo indicherebbe che 'NativeArray' non era esattamente come suggerisce il nome. –

risposta

8

Dimenticavo: Object.prototype.toString.call(a) rendimenti [object Array]

Okay, questo è le informazioni cruciali. Questo ci dice che l'array è davvero un array, è solo che è stato inizializzato da un costruttore Array in un ambito diverso da quello per il quale la funzione sta testando, esattamente come se stessimo testando un array da una finestra contro il Array di un'altra finestra costruttore in un'applicazione basata su browser. Ad esempio, esiste un problema di ambito.

provare a sostituire

Object[] fArgs = new Object[]{ new NativeArray(0) }; 

con

Object[] fArgs = new Object[]{ cx.newArray(scope, 0) }; 

... per garantire la corretta Array costruttore viene utilizzato. Perché sei andato direttamente al costruttore NativeArray, hai aggirato garantire che la sua portata è giusto, e quindi del constructor oggetto array è unArray costruttore, ma non lo stessoArray costruttore come quello sul oggetto globale la funzione vede.

+0

L'ho appena scoperto, anche se potrei giurare di averlo provato prima oggi. Grazie! – n3rd

1

Per coloro che sono intenzionalmente creando una diversa sottoclasse dell'attuazione array, e quindi non può utilizzare cx.newArray, cosa si può fare è: aggiungere questa linea ScriptRuntime.setBuiltinProtoAndParent(fArgs, scope, TopLevel.Builtins.Array);

Problemi correlati