admin管理员组

文章数量:1312967

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?

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?

Share Improve this question asked Jul 9, 2009 at 14:33 HermsHerms 38.9k13 gold badges79 silver badges104 bronze badges 3
  • If you do end up copying the arguments into an array, here's a shorter method: var a = Array.prototype.slice.call(arguments, 0); – Blixt Commented Jul 10, 2009 at 8:45
  • I tried using slice by doing args.slice(), but got the same error. Hadn't tried going through Array.prototype though. – Herms Commented Jul 10, 2009 at 13:39
  • Also, I think I'd have to do that in the test2.html. I'm trying to avoid having any extra code in the target page at all (just the actual functions being called). – Herms Commented Jul 10, 2009 at 13:42
Add a ment  | 

4 Answers 4

Reset to default 6

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

本文标签: javascriptWhy doesn39t functionapply() work across document boundaries in IEStack Overflow