Практически все Javascript-программисты пользуются консолью в браузерах. Консоль встроена в Хром, Оперу, IE и устанавливается с Firebug в Фоксе.Но у неё есть пару неудобств, которые можно очень легко исправить. Это:
- Ошибки, когда консоль не определена
- Невозможность использовать вне контекста
- Невозможность отключить во время production
- некроссбраузерность
Исправим эти проблемы легко и быстро!
В первую очередь нам необходимо подменить объект консоли на свой объект. Оригинальную консоль сохраним в переменной
original(function () { var global = this; var original = global.console; // переопределяем консоль var console = global.console = {}; })();
Теперь необходимо реализовать все методы оригинальной консоли, если они есть:
(function () { var global = this; var original = global.console; var console = global.console = {}; // список методов var methods = ['assert', 'count', 'debug', 'dir', 'dirxml', 'error', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'trace', 'warn']; // обход все элементов массива в обратном порядке for (var i = methods.length; i--;) { // обратите внимание, что обязательно необходима анонимная функция, // иначе любой метод нашей консоли всегда будет вызывать метод 'assert' (function (methodName) { // определяем новый метод console[methodName] = function () { // только если консоль доступна и есть нужный метод if (original && methodName in original) { // вызываем оригинальный метод консоли original[methodName].apply(original, arguments); } }; })(methods[i]); } })();
Таким образом мы не только избавились от ошибок в случае неопределённой консоли, но и решили вторую проблему — возможность использования консоли вдали от контекста, например:
// При клике вызвать console.log $('#my-element').click(console.log); // Короткий алиас var log = console.log; for (var i = 0; i < 10; i++) log(i);
Без нашего переопределения что в первом, что во втором случае мы бы получили ошибку "
Illegal invocation".Следующее, что нам необходимо сделать — это добавить возможность отключение дебага во время production. Это делается двумя строчками:
(function () { // .. var console = global.console = {}; console.production = false; // ... console[methodName] = function () { // только если консоль доступна и есть нужный метод И ЕСЛИ ЭТО НЕ РАБОЧИЙ КОД if (original && methodName in original && !console.production) { // вызываем оригинальный метод консоли original[methodName].apply(original, arguments); // .. })();
Теперь, чтобы отключить дебаг-информацию, достаточно, будет вызвать следующий код где-то во время инициализации нашего приложения:
console.production = true;
Особенности браузеров
Говноосёл
IE 8 и IE 9 как всегда отличились. Если вызвать следующий код:
alert(typeof console.log);
То нормальные браузеры выведут «function», а осёл — «object». У
object нету метода apply, потому самый простой способ обойти этот баг — вызвать метод из прототипа функции. Немного магии:original[methodName].apply(original, arguments); // заменяем на: Function.prototype.apply.call(original[methodName], original, arguments);
Firebug
Firebug не позволяет переопределить стандартную переменную. Потому решается очень простым фиксом. Перед присвоением необходимо удалить свойство:
var original = global.console; var console = global.console = {}; // => var original = global.console; delete global.console; var console = global.console = {};
Добавляем новые методы
Многие знают, что в самых прогрессивных браузерах нету методов time и timeEnd. Портируем их из Firebug:
// ... var original = global.console; var console = global.console = {}; if (original && !original.time) { original.time = function(name, reset){ if (!name) return; var time = new Date().getTime(); if (!console.timeCounters) console.timeCounters = {}; var key = "KEY" + name.toString(); if(!reset && console.timeCounters[key]) return; console.timeCounters[key] = time; }; original.timeEnd = function(name){ var time = new Date().getTime(); if(!console.timeCounters) return; var key = "KEY" + name.toString(); var timeCounter = console.timeCounters[key]; if (timeCounter) { var diff = time - timeCounter; var label = name + ": " + diff + "ms"; console.info(label); delete console.timeCounters[key]; } return diff; }; } // список методов var methods = // ...
Теперь даже ишаки научились считать время.
Окончательный код у нас получился следующим:
(function () { var global = this; var original = global.console; if ('console' in global) delete global.console; var console = global.console = {}; console.production = false; if (original && !original.time) { original.time = function(name, reset){ if (!name) return; var time = new Date().getTime(); if (!console.timeCounters) console.timeCounters = {}; var key = "KEY" + name.toString(); if(!reset && console.timeCounters[key]) return; console.timeCounters[key] = time; }; original.timeEnd = function(name){ var time = new Date().getTime(); if(!console.timeCounters) return; var key = "KEY" + name.toString(); var timeCounter = console.timeCounters[key]; if (timeCounter) { var diff = time - timeCounter; var label = name + ": " + diff + "ms"; console.info(label); delete console.timeCounters[key]; } return diff; }; } var methods = ['assert', 'count', 'debug', 'dir', 'dirxml', 'error', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log', 'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd', 'trace', 'warn']; for (var i = methods.length; i--;) { (function (methodName) { console[methodName] = function () { if (original && methodName in original && !console.production) { Function.prototype.apply.call(original[methodName], original, arguments); } }; })(methods[i]); } })();
Теперь консоль не вызывает ошибок, её можно использовать вне контекста, отключать на боевом сервере и считать время в IE)
Пользуйтесь на здоровье, лицензия на код — LGPL/MIT, лицензия на текст — CC BY 3.0
Github: github.com/theshock/console-cap
