Функция «apply» Javascript не существует в объекте расширения window.external - PullRequest
5 голосов
/ 29 июня 2011

Я использую расширение javascript (AKA window.external ) в IE8 (может быть и в любой версии IE) для предоставления определенных функций.
Я пытаюсь вызвать функцию apply , которая (предполагается, согласно здесь ) изначально встроена в каждую функцию JS, в window.external функция объекта, но браузер продолжает выдавать исключение, что apply функция не существует для этой функции.

Например, этот код работает:

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");

Суть в том, что мне нужно передать неизвестное количество аргументов внешней функции, и пока я зашел в тупик ...

Есть идеи?

EDIT:
Я принял ответ Майка Самуэля, поскольку (насколько я понимаю) функция apply не существует в объекте window.external, потому что это не нативный объект javascript.
То, что Майк предложил как «наихудший случай», - это то, чем я в данный момент занимаюсь.
спасибо

Ответы [ 2 ]

10 голосов
/ 29 июня 2011

Если 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]);
    ...
  }
}
1 голос
/ 10 июня 2017

На самом деле есть общее решение.Простой пример приведен ниже:

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})();
}

// make a call:
invoke('foo', 10, 'abc', new Date(), function () {});
// equivalent to:
// window.external.foo(10, 'abc', new Date(), function () {});

Я использовал формат ES6 здесь, чтобы облегчить понимание кода.И, конечно, чтобы заставить его работать в IE8, вы можете перевести его в ES5-совместимый формат, и вы должны сначала включить шим ES5 для полифилла Function.prototype.bind.

РЕДАКТИРОВАТЬ: IE8-совместимая версия:

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();
}
...