2010-05-09 90 views
13

我試圖在System.Windows.Forms.WebBrowser控件中顯示帶有嵌入式JavaScript代碼的HTML頁面。預計JavaScript代碼將通過window.external對象與嵌入環境進行交互。在調用方法window.external之前,JavaScript應該檢查方法的存在。如果它不在那裏,代碼應該調用一個通用的回退方法。在檢查typeof時調用window.external的無參數方法

// 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以防止發生方法調用?

+0

您是否嘗試過使用typeof作爲運算符而不是函數? 'typeof window.external.MyMethod!==「undefined」' – 2010-05-09 14:50:48

+0

任何回答這個問題的人都需要**在IE瀏覽器上用'window.external'嘗試他們的解決方案** - 測試Javascript上對象存在的常規方法不適用於'window.external'。 – funkybro 2013-08-13 07:17:40

回答

9

我還沒有調試您的具體情況之一,但我相信我的精神力量可以計算出這到底是怎麼回事。

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的語義。

+0

嗨,Eric,謝謝你的優秀回覆。自從我昨天從2004年閱讀您的博客評論(http://discuss.techinterview.org/default.asp?joel.3.18644.7)以來,我預計這種情況會在幕後發生。我猜,COM的東西是在WebBrowser控件的某個地方實現的,不是嗎?我將無法在另一個查找處理中進行修補?或者我可以顯式標記一個方法爲「COM作爲方法而不是屬性」? – janko 2010-05-09 15:17:11

+0

如果是這樣,您可以嘗試在C#類中使用'IDispatch'實現。首先,我會嘗試'IDispatchImpl'屬性 - 嘗試將其設置爲'CompatibleImpl'和'InternalImpl'並查看是否有任何一種方法可行。或者,你可以提供你自己的'IDispatch'實現 - 標記你的對象'[ClassInterface(ClassInterfaceType.None)]',並明確實現'IDispatch'。我也懷疑(不知道).NET 4.0的'IDynamicObject'可能用於'IDispatch'映射。 – 2010-05-10 22:59:00

-1

我實際上不確定它是否有幫助,但請嘗試window.external["MyMethod"]

如果這沒有幫助,請嘗試將此值存儲在變量中,然後只檢查該變量的類型。看看是否有幫助。

+0

不幸的是,這兩種變體都不起作用。 'window.external [「MyMethod」]'調用它,以及'var f = window.external [「MyMethod」]'。 – janko 2010-05-09 14:51:03

0

嘗試這些

/* 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")) {.... 
+0

嗨肖恩,你的'isHostMethod'也不起作用。行'object [property]'仍然調用該方法。 – janko 2010-05-09 15:21:42

6

我發現這個

if ('MyMethod' in window.external) 

不會調用的MyMethod

+0

但是這並沒有多大幫助,如果'window.external'不存在,腳本將會失敗。 – funkybro 2013-08-07 14:09:05

+0

@funkybro在這種情況下,您只需添加額外的支票, 'if(window.external &&'window.external中的'MyMethod')'。 – erdomke 2013-08-12 20:02:42

+0

是真的,但是如果你在下面看到我的答案,那就是'window.external'本身會在IE上失敗。 – funkybro 2013-08-13 07:16:03

0

這種效應可在桌面Internet Explorer中看到。腳本如:

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

將盡快達到external失敗。

看來,window.external不是一個普通的Javascript對象,它是一個VBScript對象。因此

所以報表如window.externalwindow['external']是的VBScript語句 - 和,埃裏克大號說,window.external在VBScript相當於window.external()

強大的混亂。它似乎也是在Internet Explorer上以這種方式表現的唯一對象。

對於跨瀏覽器的移動Web應用程序,其使用的IE Mobile的window.external.Notify()與原生的Windows Phone 8的溝通,但是這也將要設置在iOS document.location,測試爲window.external.Notify的存在似乎是合乎邏輯 - 但由於這個原因不起作用。

我還沒有找到預防這種方法;在script標籤中指定type="text/javascript"時仍然發生。

0

所以真的唯一的選擇是變通辦法: 1)只是不要使用0參數功能。 2)做一個檢查功能(帶參數)來檢測是否有外部呼叫。

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

並檢查,而不是函數,如果外部函數都有或沒有那裏。 3)對於每個無參數功能,如果外部代碼在支持的功能上有所不同,可以使用僞參數或爲其添加1參數檢查功能。