使用 typeof 检查时调用 window.external 上的无参数方法
Posted
技术标签:
【中文标题】使用 typeof 检查时调用 window.external 上的无参数方法【英文标题】:No-argument method on window.external is invoked when checking with typeof 【发布时间】:2011-02-17 09:09:24 【问题描述】:我正在尝试在 System.Windows.Forms.WebBrowser
控件中显示带有嵌入 javascript 代码的 html 页面。 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
以防止发生方法调用吗?
【问题讨论】:
您是否尝试过使用 typeof 作为运算符而不是函数?typeof window.external.MyMethod !== "undefined"
回答此问题的任何人都需要在 IE 上使用 window.external
尝试他们的解决方案——在 Javascript 上测试对象是否存在的常规方法不适用于 window.external
。
【参考方案1】:
我没有调试你的确切情况,但我相信我的精神力量可以解决这里发生的事情。
JScript 语言对函数的使用 和仅仅提及 函数进行了区分。当你说
x = f;
表示“将对由 f 标识的函数的引用分配给变量 x”。它提到 f.相比之下,
x = f();
使用 f.意思是“调用f标识的函数,并将返回的值赋给x。”
简而言之,JScript 中的函数本质上就是我们认为的 C# 中委托类型的属性。
有些语言没有这种区别。在 VBScript 中,如果你说x = f
并且 f 是一个函数,那就意味着调用该函数,与x = f()
相同。 VBScript 并没有在语法上对函数的使用和提及进行严格区分。
这一切的实现方式是我们使用 COM;具体来说,我们使用 OLE 自动化。在调度对象的字段以获取其值时,JScript 引擎会传递表示“属性获取”或“方法调用”的标志,具体取决于它是否被使用或提及。
但是假设您正在调度的对象是在期望从 VB 调用它的情况下编写的。也许它是 用 VB 编写的。 VB 对象说“哦,我明白你在问我这个方法的价值是完全合理和合法的。因为我不明白提到一个方法和使用它之间的区别,我只是调用无论您通过哪个标志”。
我不知道是否有解决方法,但我愿意赌上一美元,即正在发生的事情是被调用的对象假设调用者需要 VB 语义。
【讨论】:
嗨,埃里克,感谢您的出色回复。自从我昨天阅读了您 2004 年的博客评论 (discuss.techinterview.org/default.asp?joel.3.18644.7) 以来,我预计会在幕后发生这样的事情。我想,COM 的东西是在 WebBrowser 控件的某个地方实现的,不是吗?我将无法修补另一个查找处理?或者我可以将一个方法显式标记为“COM 作为方法而不是属性可见”? 如果是这种情况,您可以尝试在您的 C# 类中使用IDispatch
实现。首先,我会尝试 IDispatchImpl
属性 - 尝试将其设置为 CompatibleImpl
和 InternalImpl
并查看任何一种方式是否有效。或者,您可以提供自己的IDispatch
实现——标记您的对象[ClassInterface(ClassInterfaceType.None)]
并让它显式实现IDispatch
。我也怀疑(不太清楚).NET 4.0 的IDynamicObject
可能用于IDispatch
映射。【参考方案2】:
我找到了这个
if ('MyMethod' in window.external)
不调用 MyMethod
【讨论】:
但这并没有多大帮助,如果window.external
不存在,脚本将失败。
@funkybro 在这种情况下,您需要做的就是添加一个额外的检查,例如if (window.external && 'MyMethod' in window.external)
.
是的,但是如果您在下面看到我的回答,那么在 IE 上执行 window.external
本身就会失败。
虽然 Eric 的回答解释了内部工作原理,但这个回答实际上解决了问题。非常感谢!【参考方案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")) ....
【讨论】:
嗨,肖恩,您的isHostMethod
也不起作用。 object[property]
行仍然调用该方法。【参考方案4】:
这种效果可以在桌面 Internet Explorer 中看到。一个脚本如:
for (var i in window)
console.log('window.' + i + ' = ' + window[i]);
一旦达到external
就会失败。
看来window.external
不是一个常规的Javascript 对象,它是一个VBScript 对象。
因此,window.external
和 window['external']
等语句因此是 VBScript 语句——正如 Eric L 所说,VBScript 中的 window.external
等同于 window.external()
。
非常混乱。这似乎也是唯一在 Internet Explorer 上以这种方式运行的对象。
对于使用 IE Mobile 的 window.external.Notify()
与 Windows Phone 8 上的本地通信,但还想在 ios 上设置 document.location
的跨浏览器移动 Web 应用程序,测试 window.external.Notify
的存在将看起来合乎逻辑——但由于这个原因不起作用。
我还没有找到防止这种情况的方法;在script
标签中指定type="text/javascript"
时仍然会发生这种情况。
【讨论】:
【参考方案5】:所以真正唯一的选择是变通方法: 1)只是不要使用0参数函数。 2)做一个检查函数(带一个参数)来检测是否有外部调用。
if (typeof(window.external.HasExternal(null)) != 'undefined')
并检查外部函数是否都存在而不是函数。 3) 对于您想要的每个无参数函数,如果外部代码支持的功能有所不同,要么使其使用虚假参数,要么为其添加 1 参数检查函数。
【讨论】:
【参考方案6】:我实际上不确定它是否会有所帮助,但请尝试window.external["MyMethod"]
。
如果这没有帮助,请尝试将此值存储在一个变量中,然后再检查该变量的类型。看看有没有帮助。
【讨论】:
不幸的是,这两种变体都不起作用。window.external["MyMethod"]
和 var f = window.external["MyMethod"]
调用它。以上是关于使用 typeof 检查时调用 window.external 上的无参数方法的主要内容,如果未能解决你的问题,请参考以下文章
为啥要使用 toString() 对可以使用 typeof 进行检查的参数进行类型检查?