Консоль для всех браузеров

Это попытка заставить работать синтаксис консоли FireBug’a со всеми браузерами. ИМХО кроссбраузерный дебаг звучит не ок, но это именно он! А все получилось как-то само собой когда я сегодня что-то дебажил на тестовой платформе и для того чтобы тестеры не видели ошибок прикрывал вызовы консоли заглушками.


if(window.console)
	console.log("myLog");

В общем это как-то гнило, нашел что по данному поводу пишут разработчики Prototype и jQuery, и даже сами разработчики FireBug’a склоняются к заглушкам

Уж очень мне эти затычки не нравятся. И решил я выяснить что можно с этим сделать. Уточнив с какой версии у браузеров появилась консоль (и текущую версию): IE8b2 (IE7), Opera 9.50 (9.63), Safari 1.3 (3.21), FireFox 2.0.0 (3.0.5), я принялся за работу.

Первое что приходило на ум это что-то вроде


if (!window.console) {
	window.console = {};
	window.console.log = alert;
		
}

Но не все так просто, FireBug славится тем что показывает содержимое любого объекта и может делать форматированный вывод. То есть во-первых можно сделать


console.info({a:null});

и увидеть содержимое объекта в закладке DOM, а во-вторых можно сделать форматированный вывод


console.info("string: %d %s %d", 10, "text", 10);

и увидеть строку «string: 10 text 10». В остальных же браузерах можно наблюдать только строку [object Object] и «string: %d %s %d» соответственно, кроме IE8b2, он поддерживает форматный вывод, выпендрился, блин!

Я решил начать с написания форматного вывода, но функция sprintf оказалась настолько громоздкой и избыточной что я решил обойтись небольшим регулярным выражением, для своих нужд, тем более что FireBug тоже не различает %d и %s ;) в отличие от IE8b2 который корректно выводит 0 вместо %d которому соответствует строка. Из этого вывод что достаточно использовать только %s.

Потом я решили что было бы неплохо научиться отображать содержимое объектов и массивов, для этого как нельзя хорошо подходила одна известная функция, написанная очень нелюбимым мной человеком, имя которого можете прочитать в комментарии в коде. Единственные минус этой функции в том что она не может корректно отобразить объекты типа window, на нем она уходит куда-то в глубь рекурсии и безнадежно вешает браузер. Но этот недостаток я постараюсь решить в следующей версии, если такая появиться.

Уже неплохо. Последним штрихом к портрету было прикручивание уровня дебага «log», «debug», «info», «warn», «error». Тут для меня было несколько откровений. Первое это то что массив arguments не такой уже и массив потому что содержит в себе еще и метод callee. Второе — что объект arguments прекрасно превращается в массив с помощью волшебной строки


var args = Array.prototype.slice.call(arguments);

Третье — что этот метод не работает (правильно!) в IE7 и IE8b2, а поэтому не годиться. И наконец четвертое и последние что чертов arguments не возможно обойти циклом через in нужно обязательно это делать через длину


for(var i in arguments) // fail
	alert(arguments[i]);
for(var i=0,j=arguments.length;i<j;i++) // ok
	alert(arguments[i]);

Но это все не помешало мне дописать сегодня этот скрипт и выложит его на ваше растерзание


myConsole = function(){
	var args = (function(a,x){for(var i=0,j=a.length;i<j;i++){x.push(a[i])};return x;})(arguments,[]);
	
	if (args.length>2){
		(window.opera?opera.postError:window.alert)(args.shift() +'':\\n''+ args.shift().replace(/(%[ds])/g, function(){
			return args.shift();
			})
		)
	}else{
		// автор функции dump - Дмитрий Котеров
		// http://dklab.ru/chicken/nablas/38.html
		(window.opera?opera.postError:window.alert)(args.shift() +'':\\n''+ (function dump(d,l) {
			if (l == null) l = 1;
			var s = '''';
			if (typeof(d) == "object") {
				s += typeof(d) + " {\\n";				for (var k in d) {
					for (var i=0; i<l; i++){
						s += "  ";
					}
					s += k+": " + dump(d[k],l+1);
				}
				for (var i=0; i<l-1; i++){
					s += "  ";
				}
				s += "}\\n"
			} else {
				s += "" + d + "\\n";
			}
			return s;
		})(args.shift()));
	}
}

if (window.loadFirebugConsole) { // since FireBug 1.2
	window.loadFirebugConsole();
} else if (!window.console) {
	window.console = {};
	var names = ["log", "debug", "info", "warn", "error"];
	for (var i in names){
		window.console[names[i]] = (function(name){return function(){
			myConsole.apply(null,(function(a,x){for(var i=0,j=a.length;i<j;i++){x.push(a[i])};return x;})(arguments,[name]))
		}})(names[i]);
	}
}

Кому пригодиться пишите в каменты…