Javascript:forked函数声明效率有多高?

我刚刚阅读了这篇关于命名函数表达式及其与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
s函数。它会更长,但在我看来更容易理解(虽然我来自C / C ++ / Java)。 我希望答案包括一些测试数字或解释这些函数在运行时如何不同。     
已邀请:
       Javascript:forked函数声明效率有多高?    除非使用JIT /运行时完成任何魔术优化,否则调用任何函数都会“花费”相同的成本。函数只是通常存储在变量(或属性)中的对象。 返回特定函数对象的版本“高效”多少取决于包括(但不限于)的因素: 执行结果函数的次数(1x =无增益)和 分支与其他代码的“成本”(取决于)和 创造所述封闭的“成本”(非常便宜) 对于廉价分支或少量执行计数,“效率”降低。如果有一个特定的用例,那么基准测试就会得到“答案”。        当我看到这一点时,我的直接反应是维持这一点很糟糕。以这种方式编写的代码并不能真正理解为易于理解。    这个例子不一定正义,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)
快乐的编码。     
它非常有效。注意最后的
();
。这将立即执行外部函数的结果并将其分配给
contains
。每次使用函数
contains
时,它比执行底层逻辑更有效。 而不是每次调用
contains()
都会调用
compareDocumentPosition
,而是在代码首次执行时执行一次。
compareDocumentPosition
存在或不存在的事实不会改变,因此只检查一次是理想的。     
提到的主要优点是速度。具有嵌套
if
s的单个函数意味着每次调用函数时都需要重新评估条件。但是,我们知道条件的结果永远不会改变。 如果您担心可读性,可以通过更易读的方式实现类似的效果:
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中最好的方法。 可能将这些函数集打包成一个“类”,在这种情况下,它将紧密映射到具有虚函数的基类和每个浏览器的多个实现......     

要回复问题请先登录注册