4

名前付き関数式と IE <= 8 との非互換性に関するこの記事を読んだところです。

特に次の 1 つのステートメントに興味があります。

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;
  };
})();

私がこれを見たとき、私の即座の反応は、これを維持するのはひどいだろうということです. このように書かれたコードは、簡単に理解できるものではありません。

この場合、外部関数が宣言された直後に呼び出される別の関数内で関数を条件付きで定義する代わりに、ネストされたifs の関数を作成できます。もっと長くなりますが、私の意見では理解しやすいと思います (私は C/C++/Java から来ていますが)。

これらの関数が実行時にどのように異なるかについて、いくつかのテスト番号または説明を含む回答を希望します。

4

4 に答える 4

3

とても効率的です。最後の に注目してください();containsこれは実行され、外側の関数の結果をすぐに割り当てます。contains関数が使用されるたびに基礎となるロジックを実行するよりもはるかに効率的です。

contains()存在するが呼び出されるたびにチェックする代わりにcompareDocumentPosition、これはコードが最初に実行されるときに 1 回行われます。存在compareDocumentPositionするか存在しないかは変わらないので、一度だけ確認するのが理想です。

于 2011-03-31T22:06:13.980 に答える
2

Javascript:フォークされた関数宣言はどれくらい効率的ですか?

JIT /ランタイムで行われた魔法の最適化を除けば、関数を呼び出すのに同じ「コスト」がかかります。 関数は、多くの場合、変数 (またはプロパティ) に格納される単なるオブジェクトです。

特殊化された関数オブジェクトを返すバージョンがどれだけ「効率的」であるかは、次のような要因に依存します (ただし、これらに限定されません)。

  1. 結果の関数が実行される回数 (1x = ゲインなし) および
  2. ブランチと他のコードの「コスト」(依存)および
  3. 上記のクロージャーを作成する「コスト」(非常に安い)

安価なブランチまたは実行回数が少ない場合、「効率」は低下します。特定のユースケースがある場合は、それをベンチマークすると「答え」が得られます。

私がこれを見たとき、私の即座の反応は、これを維持するのはひどいだろうということです. このように書かれたコードは、簡単に理解できるものではありません。

この例は、必ずしも正しいとは限りません。IMOHO は、他の理由で面倒です。たとえば、匿名の外部関数に明示的な名前を付けると、たとえば、関数式に対しても実行できますが、意図をより明確にするのに役立つと思います。最初にきれいになるようにコードを書きます。次に、パフォーマンス分析 (ベンチマーク) を実行し、必要に応じて修正します。「遅い部分」は最初に期待されたものではない可能性があります。

「理解しにくい」ということのいくつかは、この構造に慣れていないことです (ここで否定的なことを暗示しようとしているわけではありません)。一方で、私が知っているすべての言語には、よりクリーンなソリューション。

この場合、外部関数が宣言された直後に呼び出される別の関数内で関数を条件付きで定義する代わりに、ネストされた ifs の関数を書くことができます。もっと長くなりますが、私の意見では理解しやすいと思います (私は C/C++/Java から来ていますが)。

繰り返しますが、正確なケースはちょっと厄介です、IMOHO。ただし、JavaScript はC/C++/Java ではなく、第一級の値としての関数と C/C++/Java にはクロージャは存在しません (これはちょっとした嘘です。クロージャは Java でエミュレートでき、最新の C++ はサポートしています)。私の知る限り、何らかの形のクロージャー-しかし、私は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)

ハッピーコーディング。

于 2011-03-31T22:37:06.170 に答える
1

前述の主な利点は速度です。ネストされたsを持つ単一の関数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() {
        ...
    }

})();
于 2011-03-31T22:13:00.323 に答える
0

純粋な C のバックグラウンドを持っている場合、これは比較的奇妙な構造ですが、C++/Java の人にとっては既知の概念に簡単にマップできるはずです。この特定のサンプルは、基本的に、3 つの派生クラスがブラウザーごとに異なる方法で実装された抽象関数を使用した実装基本クラスです。このような場合に「if」または「switch」を使用することは、C++ でも Java でも、正確には最善の方法ではありません。

このような関数のセットは「クラス」にパッケージ化される可能性が高く、その場合、仮想関数と各ブラウザーの複数の実装を使用して基本クラスに密接にマップされます...

于 2011-03-31T22:19:07.520 に答える