Javascript: насколько эффективнее объявление разветвленной функции? - PullRequest
4 голосов
/ 01 апреля 2011

Я только что прочитал эту статью о выражениях именованных функций и их несовместимости с IE <= 8. </p>

Мне интересно одно конкретное утверждение, в частности:

Распространенный шаблон в веб-разработке - это «разветвление» определений функций на основе какого-либо теста функций, обеспечивающего наилучшую производительность.

Пример, взятый с его страницы:

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).

Я бы предпочел ответы, которые включают в себя некоторые тестовые номера или объяснения того, как эти функции будут отличаться при запускевремя.

Ответы [ 4 ]

3 голосов
/ 01 апреля 2011

Это очень эффективно. Обратите внимание на (); в самом конце. Это выполняет и присваивает результат внешней функции contains немедленно. Это гораздо эффективнее, чем выполнение базовой логики каждый раз, когда используется функция contains.

Вместо проверки каждый раз, когда вызывается contains(), существует compareDocumentPosition, это делается один раз, когда код выполняется в первый раз. Тот факт, что compareDocumentPosition существует или не существует, не изменится, поэтому идеальной будет проверка только один раз.

2 голосов
/ 01 апреля 2011

Javascript: насколько эффективнее объявление разветвленной функции?

Запрет на любую магическую оптимизацию, выполненную с использованием JIT / времени выполнения, "вызывает" ту же стоимость при вызове любой функции. Функции - это просто объекты, которые часто хранятся в переменных (или свойствах).

Насколько более "эффективной" является версия, которая возвращает специализированный функциональный объект , зависит от факторов, включая (но не ограничиваясь ими):

  1. количество выполнений результирующей функции (1x = нет усиления) и
  2. «стоимость» ветви против другого кода (зависит) и
  3. «стоимость» создания указанного замыкания (очень дешево)

При дешевой ветке или малом количестве подсчетов "эффективность" уменьшается. Если есть конкретный вариант использования , тогда отметьте эталон, который , и вы получите «ответ».

Когда я вижу это, моя немедленная реакция заключается в том, что это было бы ужасно поддерживать. Код, написанный таким образом, на самом деле не может быть легко понятным.

Этот пример не обязательно делает это справедливо, ИМХО, и является грязным по другим причинам. Я думаю, что предоставление анонимной внешней функции явного имени - это можно сделать даже для выражений функций - поможет, например, лучше прояснить намерение. Сначала напишите код, который будет чистым. Затем запустите анализ производительности (бенчмарк) и исправьте при необходимости. Вероятность того, что «медленные части» не будут такими, как первоначально ожидалось.

Часть того, что «нелегко понять», является просто недостаточным знакомством с этой конструкцией (не пытаясь подразумевать здесь что-либо негативное) - с другой стороны, каждый язык, о котором я знаю, имеет особенности, которыми злоупотребляют в случаях где есть более чистые решения.

В этом случае вместо условного определения функции внутри другой функции, которая затем вызывается сразу после объявления внешней функции, можно написать функцию вложенного ifs. Это было бы дольше, но, на мой взгляд, легче понять (хотя я пришел из C / C ++ / Java).

Опять же, точный случай немного грязный, ИМХО. Тем не менее, 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)

Удачного кодирования.

1 голос
/ 01 апреля 2011

Основным преимуществом, как упомянуто, является скорость. Наличие единственной функции с вложенным значением 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() {
        ...
    }

})();
0 голосов
/ 01 апреля 2011

Это довольно странная конструкция, если вы работаете с чистым C-фоном, но ее легко сопоставить с известными концепциями C ++ / Java.Этот конкретный пример по сути является базовым классом реализации с абстрактной функцией с 3 производными классами, реализующими его по-разному для разных браузеров.Использование «if» или «switch» для такого случая не совсем лучший подход ни в C ++, ни в Java.

Вероятно, набор таких функций будет упакован в «класс», и в таком случае он будет тесно отображатьсясоздать базовый класс с виртуальными функциями и несколькими реализациями для каждого браузера ...

...