简体   繁体   中英

Why doesn't function.apply() work across document boundaries in IE?

I'm seeing some strange behavior in IE trying to call functions in another page via function.apply().

Here's a simple test case:

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 and chrome all methods work properly.

In IE (tested in 6, 7, and 8) all but the applyArgs() and remoteApply() methods work as expected.

applyArgs() gives a "JScript object expected" error when it tries calling apply (test1.html line 11).

remoteApply() gives the same "JScript object expected" error when it tries calling apply (test2.html line 5).

Problem is, I need to be able to use apply(). I can get around the issue by doing something like the remoteApplyCopy() mechanism, but I'm trying to avoid that. Why doesn't apply() just work?

You need to have the arrays created in the other window, because each window has its own Array constructor. I think this will work.

Add this function to test2.html:

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

And this function to 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;
}

Then do this:

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

Note, it seems like you should be able to do

var newArray = new win.Array();

within the test1.html cloneToRemote() function, but I couldn't make that work. If you could do that, you could get rid of the new getEmptyArray() function in test2.html.

I have no idea why this works, but I was playing around with your code and stumbled across one solution... put test2's functions inside of test1 and it works:

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

I'll let you know if I can figure out any more (IE is weird like that). Like I said, I was just toying with the code.

If you change test2.html testApply() function as follows:

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

remoteApply() works. But, applyArgs() still failed.

"... applyArgs() gives a "JScript object expected" error when it tries calling apply (test1.html line 11). remoteApply() gives the same "JScript object expected" error when it tries calling apply (test2.html line 5). ..."

Which exact object is not "JScript object" as "expected" ?

(hint: use debugger)

--DBJ

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM