Метод no-argument для window.external вызывается при проверке с помощью typeof

Я пытаюсь отобразить HTML-страницу со встроенным кодом JavaScript внутри элемента управления System.Windows.Forms.WebBrowser. Ожидается, что код JavaScript будет взаимодействовать со средой внедрения через объект window.external. Прежде чем вызывать метод на window.external, JavaScript должен проверить наличие метода. Если его нет, код должен вызывать общий метод резервного копирования.

// basic idea
if (typeof(window.external.MyMethod) != 'undefined') {
    window.external.MyMethod(args);
} else {
    window.external.Generic("MyMethod", args);
}

Однако проверка метода без аргументов с помощью typeof, похоже, уже вызывает этот метод. То есть, если MyMethod принимает любое положительное число аргументов, код выше будет работать отлично; но если MyMethod - метод без аргументов, то выражение typeof(window.external.MyMethod) не будет проверять его тип, но также вызывает его.

Есть ли какая-нибудь работа вокруг этого поведения? Можно ли каким-то образом избежать выражения window.external.MyMethod, чтобы предотвратить вызов метода?

Ответы

Ответ 1

Я не отлаживал вашу точную ситуацию, но я считаю, что мои психические силы могут решить, что здесь происходит.

Язык JScript делает различие между использованием функции и простым упоминанием об этом. Когда вы скажете

x = f;

который говорит: "Назначьте ссылку на функцию, определенную f переменной x". В нем упоминается f. Напротив,

x = f();

использует f. Это означает "вызвать функцию, идентифицированную с помощью f, и присвоить возвращаемое значение x".

Короче говоря, функции в JScript - это то, что мы будем рассматривать как свойства типа делегата в С#.

Некоторые языки не делают этого различия. В VBScript, если вы говорите x = f, а f - это функция, это значит вызвать функцию, такую ​​же, как x = f(). VBScript синтаксически не делает сильного различия между использованием и упоминанием функции.

Как все это реализовано, мы используем COM; в частности, мы используем OLE Automation. При отправке поля объекта, чтобы получить его значение, движок JScript передает флаги, которые означают либо "свойство get", либо "invoke метода", в зависимости от того, было ли оно использовано или упоминалось.

Но предположим, что отправляемый объект был написан с ожиданием, что он будет вызван из VB. Возможно, это было написано в VB. Для объекта VB вполне разумно и легально сказать: "О, я вижу, вы спрашиваете меня о значении этого метода. Поскольку я не понимаю разницы между упоминанием метода и его использованием, я просто вызову это независимо от того, какой флаг вы проходите".

Я не знаю, есть ли обходной путь, но я бы поставил столько же, сколько доллар, что то, что происходит, является вызываемым объектом, предполагается, что вызывающий пользователь хочет семантику VB.

Ответ 2

Я нашел это

if ('MyMethod' in window.external)

не вызывает MyMethod

Ответ 3

Попробуйте один из этих

/* Methods for feature testing
 * From http://peter.michaux.ca/articles/feature-detection-state-of-the-art-browser-scripting
 */
function isHostMethod(object, property){
    var t = typeof object[property];
    return t == 'function' ||
    (!!(t == 'object' && object[property])) ||
    t == 'unknown';
}

function isHostObject(object, property){
    return !!(typeof(object[property]) == 'object' && object[property]);
}

if (isHostObject(window.external, "MyMethod")) {....

Ответ 4

Этот эффект можно увидеть в настольном Internet Explorer. A script, например:

for (var i in window) {
    console.log('window.' + i + ' = ' + window[i]);
}

завершится с ошибкой, как только будет достигнуто значение external.

Похоже, что window.external не является регулярным объектом Javascript, это объект VBScript.

Таким образом, такие выражения, как window.external и window['external'] , являются операторами VBScript, и, как говорит Эрик L, window.external в VBScript эквивалентен window.external().

Могучий сбивать с толку. Похоже, что это единственный объект, который ведет себя таким образом в Internet Explorer.

Для мобильных браузеров с несколькими браузерами, которые используют IE Mobile window.external.Notify() для связи с native на Windows Phone 8, но которые также хотели бы установить document.location на iOS, тестирование на существование window.external.Notify было бы кажется логичным - но не работает по этой причине.

Я не нашел способа предотвратить это; это все еще происходит при указании type="text/javascript" в теге script.

Ответ 5

Таким образом, единственный выбор - это обходные пути: 1) Просто не используйте 0 функций параметров. 2) Сделайте функцию проверки (принимая параметр), чтобы определить, есть ли внешний вызов.

if (typeof(window.external.HasExternal(null)) != 'undefined')

и проверьте, что вместо функции, если внешние функции находятся либо там, либо нет. 3) Для каждой функции без параметров вы хотите либо использовать фиктивный параметр, либо добавить для него 1 функцию проверки параметров, если внешний код меняется в том, какие функции он поддерживает.

Ответ 6

Я действительно не уверен, что это поможет, но попробуйте window.external["MyMethod"].

Если это не помогает, попробуйте сохранить это значение в переменной и только затем проверьте тип этой переменной. Посмотрите, поможет ли это.