簡體   English   中英

Javascript:forked函數聲明效率有多高?

[英]Javascript: how much more efficient is forked function declaration?

我剛剛閱讀了這篇關於命名函數表達式及其與IE <= 8的不兼容性的文章

我特別好奇一個陳述:

Web開發中的一種常見模式是基於某種特征測試來“分叉”函數定義,從而實現最佳性能。

從他的頁面中摘取的一個例子:

var contains = (function() {
  var docEl = document.documentElement;

  if (typeof docEl.compareDocumentPosition != 'undefined') {
    return function(el, b) {
      return (el.compareDocumentPosition(b) & 16) !== 0;
    };
  }
  else if (typeof docEl.contains != 'undefined') {
    return function(el, b) {
      return el !== b && el.contains(b);
    };
  }
  return function(el, b) {
    if (el === b) return false;
    while (el != b && (b = b.parentNode) != null);
    return el === b;
  };
})();

當我看到這一點時,我的直接反應是維持這一點很糟糕。 以這種方式編寫的代碼並不能真正理解為易於理解。

在這種情況下,不是在聲明外部函數之后立即調用的另一個函數中有條件地定義函數,而是可以編寫嵌套if函數。 它會更長,但在我看來更容易理解(雖然我來自C / C ++ / Java)。

我希望答案包括一些測試數字或解釋這些函數在運行時如何不同。

它非常有效。 注意(); 在最后。 這將執行並分配外部函數的結果以立即contains 每次使用函數contains時,它比執行底層邏輯更有效。

而不是每次都檢查contains()是否存在compareDocumentPosition存在,這在代碼首次執行時完成。 compareDocumentPosition存在或不存在的事實不會改變,因此只檢查一次是理想的。

Javascript:forked函數聲明效率有多高?

除非使用JIT /運行時完成任何魔術優化,否則調用任何函數都會“花費”相同的成本。 函數只是通常存儲在變量(或屬性)中的對象。

返回特定函數對象的版本“高效”多少取決於包括(但不限於)的因素:

  1. 執行結果函數的次數(1x =無增益)和
  2. 分支與其他代碼的“成本”(取決於)和
  3. 創造所述封閉的“成本”(非常便宜)

對於廉價分支或少量執行計數,“效率”降低。 如果有一個特定的用例 ,那么基准測試就會得到“答案”。

當我看到這一點時,我的直接反應是維持這一點很糟糕。 以這種方式編寫的代碼並不能真正理解為易於理解。

這個例子不一定正義,IMOHO並且因其他原因而變得混亂。 我認為給匿名外部函數一個明確的名稱 - 即使對於函數表達式也可以這樣做 - 例如,有助於更好地澄清意圖。 編寫代碼首先要清理。 然后運行性能分析(基准測試)並根據需要進行修復。 機會是“緩慢的部分”將不是最初預期的。

其中一些“不容易理解”只是缺乏對這種結構的熟悉(並不試圖暗示任何負面的東西) - 另一方面,我所知道的每種語言都有濫用的特征。清潔解決方案

在這種情況下,不是在聲明外部函數之后立即調用的另一個函數中有條件地定義函數,而是可以編寫嵌套ifs的函數。 它會更長,但在我看來更容易理解(雖然我來自C / C ++ / Java)。

再一次,確切的情況有點混亂,IMOHO。 但是,JavaScript 不是 C / C ++ / Java,並且C / C ++ / Java中不存在函數作為第一類值和閉包(這有點白,謊言可以用Java模擬,最新的C ++支持某種形式的閉包AFAIK - 但我不使用C ++)。

因此,這種結構在其他語言中看不到,因為其他語言不容易 (或者根本) 不支持它 - 它一般都沒有說明該方法的可行性(在JavaScript或其他地方)。

我希望答案包括一些測試數字或解釋這些函數在運行時如何不同。

往上看。


擴展到頂部的粗體部分:

函數是“只是一個對象”,使用(...)運算符“應用”(讀取:調用)。

function x () {
   alert("hi")
}
x() // alerts
window.x() // alerts -- just a property (assumes global scope above)
a = {hello: x}
a.hello() // alerts (still property)
b = a.hello
b() // alerts (still just a value that can be invoked)

快樂的編碼。

提到的主要優點是速度。 具有嵌套if的單個函數意味着每次調用函數時都需要重新評估條件。 但是,我們知道條件的結果永遠不會改變。

如果您擔心可讀性,可以通過更易讀的方式實現類似的效果:

var contains = (function () {
    var docEl = document.documentElement;
    if (typeof docEl.compareDocumentPosition != 'undefined') {
        return contains_version1;
    } else if (typeof docEl.contains != 'undefined') {
        return contains_version2;
    } else {
        return contains_version3;
    }

    function contains_version1() {
        ...
    }

    function contains_version2() {
        ...
    }

    function contains_version3() {
        ...
    }
})();

要么:

(function () {
    var docEl = document.documentElement;
    var contains =
        typeof docEl.compareDocumentPosition != 'undefined' ? contains_version1 :
        typeof docEl.contains != 'undefined' ? contains_version2 :
        contains_version3;

    function contains_version1() {
        ...
    }

    function contains_version2() {
        ...
    }

    function contains_version3() {
        ...
    }

})();

如果您來自純C背景,這是相對奇怪的構造,但應該很容易映射到C ++ / Java人的已知概念。 這個特定的示例本質上是具有抽象函數的實現基類,其中3個派生類為不同的瀏覽器實現不同的類。 對於這種情況使用“if”或“switch”並不是C ++和Java中最好的方法。

可能將這些函數集打包成一個“類”,在這種情況下,它將緊密映射到具有虛函數的基類和每個瀏覽器的多個實現......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM