2009-07-09 9 views
5

Sto osservando un comportamento strano in IE cercando di chiamare le funzioni in un'altra pagina tramite function.apply().Perché does.apply() non funziona sui limiti del documento in IE?

Ecco un semplice caso di test:

Test1.html:

<HTML> 
<HEAD> 
<script language="javascript" type="text/javascript"> 
    var opened = null; 

    function applyNone() { 
    opened.testFunc.apply(opened); 
    } 

    function applyArgs() { 
    opened.testFunc.apply(opened, ["applied array"]); 
    } 

    function call() { 
    opened.testFunc("called directly"); 
    } 

    function remoteApply() { 
    opened.testApply(["used remote apply"]); 
    } 

    function remoteApplyCopy() { 
    opened.testApplyCopy(["used remote apply copy"]); 
    } 

    function openPopup() { 
    opened = window.open("test2.html", "_blank"); 
    } 
</script> 
</HEAD> 
<BODY> 
    <a href="#" onclick="openPopup()">OPEN</a> 
    <hr> 
    <a href="#" onclick="applyNone()">applyNone</a> 
    <a href="#" onclick="applyArgs()">applyArgs</a> 
    <a href="#" onclick="call()">call</a> 
    <a href="#" onclick="remoteApply()">remoteApply</a> 
    <a href="#" onclick="remoteApplyCopy()">remoteApplyCopy</a> 
</BODY> 
</HTML> 

Test2.html:

<HTML> 
<HEAD> 
<script language="javascript" type="text/javascript"> 
    function testApply(args) { 
    testFunc.apply(this, args); 
    } 

    function testApplyCopy(args) { 
    var a = []; 
    for(var i = 0; i < args.length; i++) { 
     a.push(args[i]); 
    } 
    testFunc.apply(this, a); 
    } 

    function testFunc() { 
    var s = "Got: "; 
    for(var i = 0; i < arguments.length; i++) { 
     s += arguments[i] + " "; 
    } 
    document.getElementById("output").innerHTML += s + "<BR>"; 
    } 
</script> 
</HEAD> 
<BODY> 
    Hi there 
    <div id="output"/> 
</BODY> 
</HTML> 

In Firefox e Chrome tutti i metodi di funzionare correttamente.

In IE (testato in 6, 7 e 8) tutti i metodi applyArgs() e remoteApply() funzionano come previsto.

applyArgs() restituisce un errore "oggetto JScript previsto" quando tenta di chiamare apply (test1.html riga 11).

remoteApply() restituisce lo stesso errore "oggetto JScript previsto" quando tenta di chiamare apply (test2.html riga 5).

Il problema è che devo essere in grado di utilizzare apply(). Posso aggirare il problema facendo qualcosa come il meccanismo RemoteApplyCopy(), ma sto cercando di evitarlo. Perché non si applica() funziona?

+0

Se si finisce di copiare il argomenti in un array, ecco un metodo più breve: 'var a = Array.prototype.slice.call (argomenti, 0);' – Blixt

+0

Ho provato a usare slice facendo args.slice(), ma ho ottenuto lo stesso errore. Ho provato comunque a passare attraverso Array.prototype. – Herms

+0

Inoltre, penso che dovrei farlo nel test2.html. Sto cercando di evitare di avere del codice in più nella pagina di destinazione a tutto (solo le funzioni effettive vengono chiamate). – Herms

risposta

6

È necessario disporre degli array creati nell'altra finestra, poiché ogni finestra ha il proprio costruttore di array. Penso che questo funzionerà.

Aggiungi questa funzione per Test2.html:

function getEmptyArray() { 
    return new Array(); 
} 

E questa funzione per Test1.html:

Array.prototype.cloneToRemote = function (win) { 
    var newArray = win.getEmptyArray(); 
    for (var i = 0; i < this.length; i++) 
    { 
     newArray.push(this[i]); 
    } 
    return newArray; 
} 

poi fare questo:

function applyArgs() { 
    opened.testFunc.apply(opened, ["applied array"].cloneToRemote(opened)); 
} 

nota, sembra che dovresti essere in grado di fare

var newArray = new win.Array(); 

all'interno della funzione test1.html cloneToRemote(), ma non ho potuto farlo funzionare. Se si potesse fare ciò, si potrebbe sbarazzarsi della nuova funzione getEmptyArray() in test2.html.

+0

Interessante. Non avevo considerato che le finestre avrebbero ciascuna il proprio costruttore di array. Ha senso dopo averlo pensato, e spiega un po 'il comportamento (anche se penso che dovrebbe funzionare ancora bene, come in Firefox e Chrome). Non ho tempo di provarlo adesso, ma lo terrò a mente. – Herms

+0

Dove l'hai saputo? Hai qualche riferimento? –

0

Non ho idea del perché questo funziona, ma stavo giocando in giro con il tuo codice e imbattuto in un'unica soluzione ... mettere le funzioni di test2 all'interno di test1 e funziona:

<HTML> 
<HEAD> 
<script language="javascript" type="text/javascript"> 
    var opened = null; 

    function applyArgs() { 
    testFunc.apply(opened, ["applied array"]); 
    } 

    function openPopup() { 
    opened = window.open("test2.html", "_blank"); 
    } 

    function testFunc() { 
    var s = "Got: "; 
    for(var i = 0; i < arguments.length; i++) { 
     s += arguments[i] + " "; 
    } 
    this.document.getElementById("output").innerHTML += s + "<BR>"; 
    } 
</script> 
</HEAD> 
<BODY> 
    <a href="#" onclick="openPopup()">OPEN</a> 
    <hr> 
    <a href="#" onclick="applyArgs()">applyArgs</a> 
</BODY> 
</HTML> 

ti lascio sapere se riesco a capire di più (IE è strano come quello). Come ho detto, stavo solo giocando con il codice.

+0

Sì, sembra che il problema è che gli array in qualche modo perdono le informazioni sul tipo di array quando vengono passati tra le pagine (quindi perché RemoteApply fallisce ma RemoteApplyCopy funziona). – Herms

+0

Bene, la variabile "arguments" nelle funzioni non è in realtà una matrice; è un oggetto simile ad un array con un attributo length. Non penso che sia il problema principale, neanche; l'errore IE proviene da test1.html, quando tenta di chiamare la funzione in primo luogo con un array. –

+0

I due test che hanno esito negativo stanno passando un array attraverso i limiti della pagina e utilizzando quello per chiamare apply. Dal momento che tutto il resto funziona, sembra che questo sia il problema principale. È come se IE stia cercando di verificare il secondo argomento da applicare() e sta vedendo qualcosa che non pensa sia un oggetto valido. – Herms

0

Se si cambia la funzione Test2.html testApply() come segue:

function testApply() { 
    testFunc.apply(this, arguments); 
} 

remoteApply() funziona. Ma ancora applyArgs() non è riuscito.

+0

che tuttavia modifica il comportamento. La modifica causerà a testFunc di ottenere un array come argomento, non la stringa presente nell'array. – Herms

0

"... applyArgs() restituisce un errore" oggetto JScript previsto "quando tenta di chiamare apply (test1.html riga 11). remoteApply() restituisce lo stesso errore "oggetto JScript previsto" quando tenta di chiamare apply (test2.html riga 5). ..."

Quale oggetto esatto non è "oggetto JScript" come "previsto"

? (Suggerimento: debugger uso)

--DBJ