目錄
或者我們……?
ActiveX 對象
映射到 DOM 屬性的 HTML 屬性
對用戶行為的假設
完全不起作用的東西
選擇測試語法
關於 JavaScript 特性檢測的常見問題
什麼是 JavaScript 特性檢測,為什麼它很重要?
JavaScript 特性檢測是如何失敗的?
特性檢測和瀏覽器檢測有什麼區別?
如何使用 JavaScript 檢測移動設備?
什麼是 Feature.js,它如何幫助進行特性檢測?
什麼是 Modernizr,它如何幫助進行特性檢測?
如何使用 device-detector-js 包進行特性檢測?
實施特性檢測的一些最佳實踐是什麼?
特性檢測能否幫助提高網站性能?
如何了解不同瀏覽器支持的最新特性?
首頁 web前端 js教程 當JavaScript功能檢測失敗時

當JavaScript功能檢測失敗時

Feb 22, 2025 am 09:57 AM

When JavaScript Feature Detection Fails

關鍵要點

  • JavaScript 的特性檢測(測試程序員想要使用的特性)並不總是可靠的。例如,在 Internet Explorer 中測試 ActiveXObject 以進行 Ajax 請求、映射到 DOM 屬性的 HTML 屬性以及對用戶行為的假設(例如檢測觸摸設備)等。
  • 當特性檢測失敗時,有時需要採用瀏覽器檢測。但是,建議使用專有對象測試而不是 navigator 信息,並將其用於排除瀏覽器而不是包含瀏覽器。
  • 在實現瀏覽器檢測時,務必極其小心。始終首先假設完全符合特性測試,只有在知道某個特性無法按預期工作時才求助於瀏覽器檢測。此外,用於對象和特性測試的語法會影響檢測的成功率,因此選擇正確的語法至關重要。

曾經,瀏覽器檢測是 JavaScript 程序員的看家本領。如果我們知道某些功能在 IE5 中有效但在 Netscape 4 中無效,我們會測試該瀏覽器並相應地修改代碼。例如:

if (navigator.userAgent.indexOf('MSIE 5') != -1) {
  // 我们认为此浏览器是 IE5
}
登入後複製
登入後複製
登入後複製
登入後複製

但是,當我第一次加入這個行業時,軍備競賽就已經開始了!供應商正在向用戶代理字符串添加額外的值,因此它們看起來像是其競爭對手的瀏覽器,也是它們自己的瀏覽器。例如,這是 Mac 版 Safari 5:

<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
登入後複製
登入後複製
登入後複製
登入後複製

這將匹配對“Safari”、“Webkit”以及“KHTML”(Webkit 基於的Konqueror 代碼庫)的測試;但它也匹配“Gecko”(這是Firefox 的渲染引擎),當然還有“Mozilla ”(由於歷史原因,幾乎每個瀏覽器都聲稱自己是Mozilla)。

添加所有這些值的目的是規避瀏覽器檢測。如果腳本假設只有 Firefox 才能處理特定功能,否則可能會排除 Safari,即使它可能也能工作。別忘了用戶自己可以更改他們的用戶代理——我曾經將我的瀏覽器設置為識別為“Googlebot/1.0”,這樣我就可以訪問網站所有者認為僅供抓取的內容!

因此,隨著時間的推移,這種瀏覽器檢測已成為一個不可能解開的亂麻,並且在很大程度上已不再使用,取而代之的是更好的東西——特性檢測。

特性檢測只是測試我們想要使用的特性。例如,如果我們需要getBoundingClientRect(獲取元素相對於視口的位置),那麼重要的是瀏覽器是否支持它,而不是它是哪個瀏覽器;因此,與其測試受支持的瀏覽器,不如測試特性本身:

if (typeof document.documentElement.getBoundingClientRect != "undefined") {
  // 浏览器支持此函数
}
登入後複製
登入後複製
登入後複製
登入後複製

不支持該函數的瀏覽器將返回“undefined”類型,因此不會通過條件。無需在任何特定瀏覽器中測試腳本,我們就知道它要么正確工作,要么靜默失敗。

或者我們……?

但事實是——特性檢測也不是完全可靠的——有時它會失敗。因此,讓我們現在看看一些示例,看看我們可以做些什麼來解決每個案例。

ActiveX 對象

也許特性檢測失敗最著名的例子是測試 ActiveXObject 以在 Internet Explorer 中進行 Ajax 請求。

ActiveX 是後期綁定對象的示例,其實際意義是您無法知道它是否受支持直到您嘗試使用它。因此,如果用戶禁用了 ActiveX,則以下代碼將引發錯誤:

if (navigator.userAgent.indexOf('MSIE 5') != -1) {
  // 我们认为此浏览器是 IE5
}
登入後複製
登入後複製
登入後複製
登入後複製

要解決此問題,我們需要使用異常處理——嘗試實例化對象,捕獲任何失敗,並相應地處理它:

<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
登入後複製
登入後複製
登入後複製
登入後複製

映射到 DOM 屬性的 HTML 屬性

屬性映射通常用於測試與 HTML5 屬性一起使用的 API 的支持。例如,通過查找可拖動屬性來檢查具有 [draggable="true"] 的元素是否支持拖放 API:

if (typeof document.documentElement.getBoundingClientRect != "undefined") {
  // 浏览器支持此函数
}
登入後複製
登入後複製
登入後複製
登入後複製

這裡的問題是 IE8 或更早版本會自動將所有HTML 屬性映射到 DOM 屬性。這就是為什麼 getAttribute 在這些舊版本中如此混亂的原因,因為它根本不返回屬性,而是返回 DOM 屬性。

這意味著如果我們使用已經具有屬性的元素:

if (typeof window.ActiveXObject != "undefined") {
  var request = new ActiveXObject("Microsoft.XMLHTTP");
}
登入後複製
登入後複製
登入後複製

那麼即使它們不支持,IE8 或更早版本也會返回 true 用於 ("draggable" in element)

屬性可以是任何內容:

if (typeof window.ActiveXObject != "undefined") {
  try {
    var request = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (ex) {
    request = null;
  }
  if (request !== null) {
    //... 我们有一个请求对象
  }
}
登入後複製
登入後複製
登入後複製

但結果將相同——IE8 或更早版本將返回 true 用於 ("nonsense" in element)

在這種情況下,解決方案是使用不具有該屬性的元素進行測試,最安全的方法是使用創建的元素:

if ("draggable" in element) {
  // 浏览器支持拖放
}
登入後複製
登入後複製

對用戶行為的假設

您可能已經看到使用以下代碼來檢測觸摸設備:

<div draggable="true"> ... </div>
登入後複製

大多數觸摸設備在觸發點擊事件之前會實現人工延遲(通常約為 300 毫秒),這是為了避免在雙擊元素的同時也點擊它們。但這會使應用程序感覺遲緩且無響應,因此開發人員有時會使用該特性測試來分叉事件:

<div nonsense="true"> ... </div>
登入後複製

但是,此條件源於一個錯誤的假設——因為設備支持觸摸,因此將使用觸摸。但是觸摸屏筆記本電腦呢?用戶可能正在觸摸屏幕,也可能正在使用鼠標或觸控板;上面的代碼無法處理這種情況,因此用鼠標單擊將不會執行任何操作。

在這種情況下,解決方案根本不是測試事件支持——而是同時綁定兩個事件,然後使用 preventDefault 來阻止觸摸生成點擊:

if (navigator.userAgent.indexOf('MSIE 5') != -1) {
  // 我们认为此浏览器是 IE5
}
登入後複製
登入後複製
登入後複製
登入後複製

完全不起作用的東西

承認這一點很痛苦,但有時我們不需要測試的不是特性——而是瀏覽器——因為特定瀏覽器聲稱支持某些不起作用的東西。最近的一個例子是 Opera 12 中的 setDragImage()(這是拖放 dataTransfer 對象的一種方法)。

特性測試在這裡失敗是因為 Opera 12 聲稱支持它;異常處理也無濟於事,因為它不會引發任何錯誤。它只是不起作用:

<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
登入後複製
登入後複製
登入後複製
登入後複製

現在,如果您只想嘗試添加自定義拖動圖像,並且樂於在不支持的情況下保留默認值(這將發生),那麼這可能很好。但是,如果您的應用程序確實需要自定義圖像,以至於不支持它的瀏覽器應該使用完全不同的實現(即使用自定義 JavaScript 來實現所有拖動行為)呢?

或者,如果瀏覽器實現了某些功能,但存在無法避免的渲染錯誤呢?有時我們別無選擇,只能明確檢測有問題的瀏覽器,並將其排除在使用它本來會嘗試支持的功能之外。

因此,問題變成了——實現瀏覽器檢測最安全的方法是什麼?

我有兩點建議:

  1. 優先使用專有對象測試而不是 navigator 信息。
  2. 將其用於排除瀏覽器而不是包含瀏覽器。

例如,可以使用 window.opera 對象檢測 Opera 12 或更早版本,因此我們可以使用該排除來測試可拖動支持:

if (typeof document.documentElement.getBoundingClientRect != "undefined") {
  // 浏览器支持此函数
}
登入後複製
登入後複製
登入後複製
登入後複製

最好使用專有對象而不是標準對象,因為當發布新瀏覽器時,測試結果不太可能發生變化。以下是一些我最喜歡的示例:

if (typeof window.ActiveXObject != "undefined") {
  var request = new ActiveXObject("Microsoft.XMLHTTP");
}
登入後複製
登入後複製
登入後複製

對象測試也可以與特性測試結合使用,以確定特定瀏覽器中特定特性的支持,或者在緊急情況下,定義更精確的瀏覽器條件:

if (typeof window.ActiveXObject != "undefined") {
  try {
    var request = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (ex) {
    request = null;
  }
  if (request !== null) {
    //... 我们有一个请求对象
  }
}
登入後複製
登入後複製
登入後複製

我們已經註意到用戶代理字符串是一個不可靠的混亂,但供應商字符串實際上相當可預測,並且可以用來可靠地測試 Chrome 或 Safari:

if ("draggable" in element) {
  // 浏览器支持拖放
}
登入後複製
登入後複製

所有這一切的黃金法則是要極其小心。確保您在盡可能多的瀏覽器中測試條件,並仔細考慮它們的向前兼容性——目標是使用瀏覽器條件來排除瀏覽器,因為存在已知的錯誤,而不是因為已知的特性而包含它們(這就是特性測試的目的)

從根本上說,始終首先假設完全符合特性測試——除非您知道情況並非如此,否則假設特性將按預期工作。

選擇測試語法

在結束之前,我想檢查一下我們可以用於對象和特性測試的不同類型的語法。例如,近年來,以下語法已變得很常見:

if (navigator.userAgent.indexOf('MSIE 5') != -1) {
  // 我们认为此浏览器是 IE5
}
登入後複製
登入後複製
登入後複製
登入後複製

過去我們無法使用它,因為 IE5 及其同類產品會因語法而引發錯誤;但現在我們不必支持這些瀏覽器,這已不再是問題。

從本質上講,它與以下內容完全相同,但編寫起來更短:

<code>Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/534.59.10 (KHTML, like Gecko) Version/5.1.9 Safari/534.59.10</code>
登入後複製
登入後複製
登入後複製
登入後複製

但是,測試條件通常依賴於自動類型轉換:

if (typeof document.documentElement.getBoundingClientRect != "undefined") {
  // 浏览器支持此函数
}
登入後複製
登入後複製
登入後複製
登入後複製

我們在某些瀏覽器對象測試(例如window.opera 測試)中早些時候使用了該語法,這是安全的,因為對像如何評估——任何已定義的對像或函數都將始終評估為true,而如果它未定義,則將評估為false。

但是我們可能正在測試有效返回 null 或空字符串的東西,這兩者都評估為 false。例如,style.maxWidth 屬性有時用於排除 IE6:

if (typeof window.ActiveXObject != "undefined") {
  var request = new ActiveXObject("Microsoft.XMLHTTP");
}
登入後複製
登入後複製
登入後複製

只有在支持 maxWidth 屬性並且具有作者定義的值時,它才會評估為 true,因此如果我們這樣編寫測試,它可能會失敗:

if (typeof window.ActiveXObject != "undefined") {
  try {
    var request = new ActiveXObject("Microsoft.XMLHTTP");
  } catch (ex) {
    request = null;
  }
  if (request !== null) {
    //... 我们有一个请求对象
  }
}
登入後複製
登入後複製
登入後複製

一般規則是這樣的:依賴於自動類型轉換對於對象和函數是安全的,但對於字符串和數字或可能為 null 的值並不一定安全。

話雖如此——如果您能安全地使用它,那就這樣做,因為它在現代瀏覽器中通常要快得多(可能是因為它們針對這種類型的條件進行了優化)。

有關此內容的更多信息,請參閱:現實世界中的自動類型轉換。

關於 JavaScript 特性檢測的常見問題

什麼是 JavaScript 特性檢測,為什麼它很重要?

JavaScript 特性檢測是開發人員用來確定用戶瀏覽器是否支持特定特性或 API 的一種技術。這至關重要,因為並非所有瀏覽器都支持 JavaScript 的所有特性。通過使用特性檢測,開發人員可以為不受支持的特性提供替代解決方案或後備方案,確保網站或應用程序在不同瀏覽器上都能正確運行。這增強了用戶體驗並確保了兼容性。

JavaScript 特性檢測是如何失敗的?

JavaScript 特性檢測可能會由於多種原因而失敗。一個常見的原因是特性檢測代碼的實現不正確。例如,如果代碼檢查對像中不存在的屬性,它將返回 undefined,導致假陰性。另一個原因可能是瀏覽器的怪癖或錯誤,這可能會導致特性檢測給出不准確的結果。

特性檢測和瀏覽器檢測有什麼區別?

特性檢測涉及檢查用戶瀏覽器是否支持特定特性或 API,而瀏覽器檢測則識別用戶的瀏覽器和版本。雖然這兩種技術都旨在確保兼容性和功能性,但特性檢測通常被認為是一種更好的實踐,因為它直接檢查特性,而不是根據瀏覽器類型或版本來假設其支持。

如何使用 JavaScript 檢測移動設備?

您可以使用 JavaScript 中的 navigator.userAgent 屬性來檢測移動設備。此屬性返回一個字符串,表示瀏覽器的用戶代理標頭。通過檢查此字符串中的特定關鍵字(例如“Android”、“iPhone”或“iPad”),您可以確定用戶是否在移動設備上。

什麼是 Feature.js,它如何幫助進行特性檢測?

Feature.js 是一個輕量級、快速且簡單的 JavaScript 實用程序,用於特性檢測。它提供易於使用的 API,允許開發人員測試瀏覽器是否支持特定特性。這有助於為不受支持的特性提供後備方案或替代解決方案,從而增強網站或應用程序的兼容性和功能性。

什麼是 Modernizr,它如何幫助進行特性檢測?

Modernizr 是一個 JavaScript 庫,可幫助開發人員利用 HTML5 和 CSS3 特性,同時保持與舊版瀏覽器的兼容性。它使用特性檢測來檢查瀏覽器是否支持特定特性,並將類添加到 HTML 元素,允許您在樣式表或 JavaScript 中定位特定瀏覽器功能。

如何使用 device-detector-js 包進行特性檢測?

device-detector-js 包是用於設備檢測的強大工具。它解析用戶代理字符串並檢測智能手機、平板電腦、台式機、電視機等設備。它還檢測瀏覽器、引擎、操作系統和其他有用信息。您可以使用此包根據檢測到的設備調整網站或應用程序的行為。

實施特性檢測的一些最佳實踐是什麼?

實施特性檢測的一些最佳實踐包括:使用可靠且經過測試的庫(如Modernizr 或Feature.js)、在不同的瀏覽器和設備上徹底測試您的特性檢測代碼、為不受支持的特性提供替代解決方案或後備方案以及避免根據瀏覽器類型或版本來假設特性支持。

特性檢測能否幫助提高網站性能?

是的,特性檢測可以幫助提高網站性能。通過檢測不受支持的特性並提供替代解決方案或後備方案,您可以防止不必要的代碼在瀏覽器中運行。這可以減少加載時間並提高網站的整體性能。

如何了解不同瀏覽器支持的最新特性?

由於 Web 開發的快速發展,了解不同瀏覽器支持的最新特性可能具有挑戰性。但是,Mozilla 開發者網絡 (MDN)、Can I Use 和 JavaScript 文檔等資源可以提供有關不同瀏覽器中特性支持的最新信息。

以上是當JavaScript功能檢測失敗時的詳細內容。更多資訊請關注PHP中文網其他相關文章!

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

熱門話題

Java教學
1655
14
CakePHP 教程
1414
52
Laravel 教程
1307
25
PHP教程
1253
29
C# 教程
1228
24
神秘的JavaScript:它的作用以及為什麼重要 神秘的JavaScript:它的作用以及為什麼重要 Apr 09, 2025 am 12:07 AM

JavaScript是現代Web開發的基石,它的主要功能包括事件驅動編程、動態內容生成和異步編程。 1)事件驅動編程允許網頁根據用戶操作動態變化。 2)動態內容生成使得頁面內容可以根據條件調整。 3)異步編程確保用戶界面不被阻塞。 JavaScript廣泛應用於網頁交互、單頁面應用和服務器端開發,極大地提升了用戶體驗和跨平台開發的靈活性。

JavaScript的演變:當前的趨勢和未來前景 JavaScript的演變:當前的趨勢和未來前景 Apr 10, 2025 am 09:33 AM

JavaScript的最新趨勢包括TypeScript的崛起、現代框架和庫的流行以及WebAssembly的應用。未來前景涵蓋更強大的類型系統、服務器端JavaScript的發展、人工智能和機器學習的擴展以及物聯網和邊緣計算的潛力。

JavaScript引擎:比較實施 JavaScript引擎:比較實施 Apr 13, 2025 am 12:05 AM

不同JavaScript引擎在解析和執行JavaScript代碼時,效果會有所不同,因為每個引擎的實現原理和優化策略各有差異。 1.詞法分析:將源碼轉換為詞法單元。 2.語法分析:生成抽象語法樹。 3.優化和編譯:通過JIT編譯器生成機器碼。 4.執行:運行機器碼。 V8引擎通過即時編譯和隱藏類優化,SpiderMonkey使用類型推斷系統,導致在相同代碼上的性能表現不同。

JavaScript:探索網絡語言的多功能性 JavaScript:探索網絡語言的多功能性 Apr 11, 2025 am 12:01 AM

JavaScript是現代Web開發的核心語言,因其多樣性和靈活性而廣泛應用。 1)前端開發:通過DOM操作和現代框架(如React、Vue.js、Angular)構建動態網頁和單頁面應用。 2)服務器端開發:Node.js利用非阻塞I/O模型處理高並發和實時應用。 3)移動和桌面應用開發:通過ReactNative和Electron實現跨平台開發,提高開發效率。

Python vs. JavaScript:學習曲線和易用性 Python vs. JavaScript:學習曲線和易用性 Apr 16, 2025 am 12:12 AM

Python更適合初學者,學習曲線平緩,語法簡潔;JavaScript適合前端開發,學習曲線較陡,語法靈活。 1.Python語法直觀,適用於數據科學和後端開發。 2.JavaScript靈活,廣泛用於前端和服務器端編程。

如何使用Next.js(前端集成)構建多租戶SaaS應用程序 如何使用Next.js(前端集成)構建多租戶SaaS應用程序 Apr 11, 2025 am 08:22 AM

本文展示了與許可證確保的後端的前端集成,並使用Next.js構建功能性Edtech SaaS應用程序。 前端獲取用戶權限以控制UI的可見性並確保API要求遵守角色庫

從C/C到JavaScript:所有工作方式 從C/C到JavaScript:所有工作方式 Apr 14, 2025 am 12:05 AM

從C/C 轉向JavaScript需要適應動態類型、垃圾回收和異步編程等特點。 1)C/C 是靜態類型語言,需手動管理內存,而JavaScript是動態類型,垃圾回收自動處理。 2)C/C 需編譯成機器碼,JavaScript則為解釋型語言。 3)JavaScript引入閉包、原型鍊和Promise等概念,增強了靈活性和異步編程能力。

如何安裝JavaScript? 如何安裝JavaScript? Apr 05, 2025 am 12:16 AM

JavaScript不需要安裝,因為它已內置於現代瀏覽器中。你只需文本編輯器和瀏覽器即可開始使用。 1)在瀏覽器環境中,通過標籤嵌入HTML文件中運行。 2)在Node.js環境中,下載並安裝Node.js後,通過命令行運行JavaScript文件。

See all articles