Обнаружение возможности — это не обнаружение браузера

Наиболее часто используемая и общепринятая форма обнаружения клиентов называется обнаружением возможностей. Обнаружение возможностей (также называемое обнаружением функций) направлено не на определение конкретного используемого браузера, а на определение возможностей браузера. Этот подход предполагает, что специальные знания браузера не нужны и что решение может быть найдено путем определения того, действительно ли существует рассматриваемая возможность. Базовый шаблон для обнаружения возможностей выглядит следующим образом:

if (object.propertyInQuestion){
    // use object.propertyInQuestion
}

Например, метод DOM document.getElementById() не существовал в Internet Explorer до версии 5. Этого метода просто не существовало в более ранних версиях, хотя ту же функциональность можно было реализовать с помощью нестандартного свойства document.all. Это привело к вилке обнаружения возможностей, такой как

function getElement(id){
  if (document.getElementById){
    return document.getElementById(id);
  } else if (document.all){
    return document.all[id];
  } else {
    throw new Error("No way to retrieve element!");
  }
}

При обнаружении возможностей необходимо понимать две важные концепции. Как только что упоминалось, наиболее распространенный способ достижения результата должен быть протестирован в первую очередь. В предыдущем примере это означало тестирование на document.getElementById()before document.all. Тестирование наиболее распространенного решения обеспечивает оптимальное выполнение кода, избегая тестирования с несколькими условиями в общем случае.

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

Более безопасное обнаружение возможностей

Обнаружение возможности наиболее эффективно, когда вы проверяете не только наличие функции, но и то, что функция может вести себя соответствующим образом. Примеры в предыдущем разделе основаны на приведении типа члена тестируемого объекта для определения его присутствия. Хотя это сообщает вам о наличии члена объекта, нет никаких указаний на то, является ли член тем, который вы ожидаете. Рассмотрим следующую функцию, которая пытается определить, является ли объект сортируемым:

//AVOID! Incorrect capability detection – only checks for existence
function isSortable(object){
  return !!object.sort;
}

Эта функция пытается определить, можно ли отсортировать объект, проверяя наличие метода sort(). Проблема в том, что любой объект со свойством sort также вернет true:

var result = isSortable({ sort: true });

Простая проверка существования свойства еще не означает, что рассматриваемый объект поддается сортировке. Лучший подход - проверить, что sort на самом деле является функцией

//Better – checks if sort is a function
function isSortable(object){
  return typeof object.sort == "function";
}

Оператор typeof используется в этом коде, чтобы определить, что сортировка на самом деле является функцией и, следовательно, может быть вызвана для сортировки данных, содержащихся внутри.