2009-07-09 9 views
5

Je vois un comportement étrange dans IE essayant d'appeler des fonctions dans une autre page via function.apply().Pourquoi function.apply() ne fonctionne-t-il pas à travers les limites de document dans IE?

Voici un exemple simple de 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> 

Dans Firefox et Chrome toutes les méthodes fonctionnent correctement.

Dans IE (testé dans 6, 7 et 8), tout sauf les méthodes applyArgs() et remoteApply() fonctionnent comme prévu. ApplyArgs() donne une erreur "objet JScript attendu" lorsqu'il tente d'appeler apply (test1.html ligne 11).

RemoteApply() renvoie la même erreur "objet JScript attendu" lors de l'appel de apply (test2.html ligne 5).

Le problème est, je dois être en mesure d'utiliser apply(). Je peux contourner le problème en faisant quelque chose comme le mécanisme remoteApplyCopy(), mais j'essaie d'éviter cela. Pourquoi ne s'applique pas() juste le travail?

+0

Si vous finissez par copier le arguments dans un tableau, voici une méthode plus courte: 'var a = Array.prototype.slice.call (arguments, 0);' – Blixt

+0

J'ai essayé d'utiliser slice en faisant args.slice(), mais j'ai eu la même erreur. J'ai aussi essayé de passer par Array.prototype – Herms

+0

Aussi, je pense que je devrais faire ça dans le test2.html J'essaie d'éviter d'avoir du code supplémentaire sur la page cible tous (seulement les fonctions réelles étant appelées). – Herms

Répondre

6

Vous devez avoir les tableaux créés dans l'autre fenêtre, car chaque fenêtre possède son propre constructeur Array. Je pense que cela fonctionnera.

Ajouter cette fonction à test2.html:

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

Et cette fonction à 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; 
} 

faites ceci:

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

Remarque, il semble que vous devriez être capable de faire

var newArray = new win.Array(); 

dans la fonction cloneToRemote() test1.html, mais je ne pouvais pas faire fonctionner cela. Si vous pouviez le faire, vous pourriez vous débarrasser de la nouvelle fonction getEmptyArray() dans test2.html. ApplyArgs() donne une erreur "objet JScript attendu" lorsqu'il tente d'appeler apply (test1.html ligne 11).

+0

Intéressant. Je n'avais pas considéré que les fenêtres auraient chacune leur propre constructeur Array. Ça a du sens après y avoir réfléchi, et ça explique un peu le comportement (même si je pense que ça devrait fonctionner correctement, comme dans Firefox et Chrome). Je n'ai pas le temps de tester ça maintenant, mais je vais le garder à l'esprit. – Herms

+0

Où avez-vous entendu parler de ça? Avez-vous une référence? –

0

Je ne sais pas pourquoi cela fonctionne, mais je jouais avec votre code et trébuché à travers une solution ... mettre les fonctions de test2 intérieur de test1 et il fonctionne:

<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> 

Je vous laisse savoir si je peux comprendre plus (IE est bizarre comme ça). Comme je l'ai dit, je ne faisais que jouer avec le code.

+0

Oui, il semble que le problème est que les tableaux perdent en quelque sorte leurs informations de type tableau lorsqu'ils sont passés entre les pages (ainsi, remoteApply échoue mais remoteApplyCopy fonctionne). – Herms

+0

Eh bien, la variable "arguments" dans les fonctions n'est pas réellement un tableau; C'est un objet de type tableau avec un attribut de longueur. Je ne pense pas que ce soit le problème principal non plus; l'erreur IE vient de test1.html, quand il essaie d'appeler la fonction en premier lieu avec un tableau. –

+0

Les deux tests qui échouent transmettent un tableau sur les limites de la page et l'utilisent pour appeler apply. Puisque tout le reste fonctionne, il semble que ce soit le problème principal. C'est comme si IE essayait de vérifier le deuxième argument de apply() et voit quelque chose qu'il ne pense pas être un objet valide. – Herms

0

Si vous changez test2.html fonction testApply() comme suit:

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

remoteApply() fonctionne. Mais, applyArgs() a toujours échoué.

+0

qui change cependant le comportement. Votre changement provoquera testFunc pour obtenir un tableau en tant qu'argument, pas la chaîne qui est dans le tableau. – Herms

0

"... remoteApply() renvoie la même erreur "Objet JScript attendu" lorsqu'il tente d'appeler apply (test2.html ligne 5). ... »

Quel objet exact n'est pas "objet JScript" comme "attendu"

? (Indice: débogueur utilisation)

--DBJ

Questions connexes