Internet Explorer - javascript “apply” 函数在 window.external e

internet explorer - The Javascript "apply" function doesn't exist in window.external extension object

本文关键字:函数 window external apply Explorer javascript Internet      更新时间:2023-09-26

我在IE8上使用javascript扩展(AKA window.external(来公开某些功能。
我正在尝试调用 apply 函数,该函数(根据这里应该(本机嵌入到每个 JS 函数中,在 window.external 对象的函数上,但浏览器不断抛出异常,指出函数不存在应用函数。

例如,此代码工作:

function onDataReceived(url, success, status, data, errorMessage) {
    alert(onDataReceived);
}
function innerTest() {
    alert(arguments[0] + ", " + arguments[1]);
}
function outerTest() {
    innerTest.apply(null, arguments);
}
outerTest("hello", "world");
// alerts "hello, world"

但是此代码会引发异常:

function outerTest() {
    window.external.innerTest.apply(null, arguments); // <-- exception
}
outerTest("hello", "world");

底线是 - 我需要将未知数量的参数传递给外部函数,到目前为止我已经走到了死胡同......

有什么想法吗?

编辑:
我接受了Mike Samuel的回答,因为(据我所知(apply函数在window.external对象中不存在,因为它不是本机javascript对象。
迈克建议的"最坏情况"是我目前最终所做的。
谢谢

如果window.external是一个主机对象,或者来自某个不希望其原型公开给页面逻辑的扩展机制,那么它可能是一个函数,但可能没有通常的call和应用成员。 幸运的是,您可以致电call并申请apply

Function.prototype.apply.call(window.external, null, [argumentsToExtension])

还是真的元,

Function.prototype.apply.apply(window.external, [null, [argumentsToExtension]])

其中null是作为this的值传递的内容,应通过通常的调用/应用规则解释为window

编辑:

如果这不起作用,您可以随时退回到黑客三角形。

function triangleOfHackery(obj, methodName, args) {
  switch (args.length) {
    case 0: return obj[methodName]();
    case 1: return obj[methodName](args[0]);
    case 2: return obj[methodName](args[0], args[1]);
    case 3: return obj[methodName](args[0], args[1], args[2]);
    ...
  }
}

实际上有一个通用的解决方案。一个简单的例子如下:

function invoke (funcName, ...args) {
    var argStr = '';
    for (let i in args) {
        argStr += ', this.args[' + i + ']';
    }
    return (new Function('return window.external[''' + funcName + '''](' + argStr.substring(2) + ')')).bind({args})();
}
// define a circular structure which cannot be stringified:
const a = {}; a.a = a;
// make a call:
invoke('foo', 10, 'abc', new Date(), function(){}, a);
// equivalent to:
window.external.foo(10, 'abc', new Date(), function(){}, a);

如您所见,没有必要保持参数可序列化。

主要思想是正确指定上下文,并将所有参数挂载到该上下文中

我在这里使用了 ES6 语法,只是为了让代码更容易理解。当然,要使其在IE8中工作,您可以将其转换为与ES5兼容的语法,并且您可能首先包含ES5填充码以填充Function.prototype.bind。或者,您根本不需要bind

编辑:ES5兼容版本:

function invoke (funcName) {
    var argStr = '';
    for (var i=1; i<arguments.length; i++) {
        argStr += ', this.args[' + i + ']';
    }
    return {
        args: arguments,
        func: new Function('return window.external[''' + funcName + '''](' + argStr.substring(2) + ')')
    }.func();
}