Как безопасно обернуть `console.log`?

Предположим, что я хочу включить некоторые вызовы в console.log для какой-либо законной причины производства, скажем, для чего-то вроде жгута unit test. Очевидно, я бы не хотел, чтобы это порождало преждевременное исключение, если в браузере отсутствует консоль console или если нет.

Каков наилучший способ создать простую функцию log для записи материала на консоль или без сбоев без ошибок, если консоль отсутствует?

Принятый ответ на вопрос, связанный выше:

var log = Function.prototype.bind.call(console.log, console);
log.apply(console, ["this", "is", "a", "test"]);

Может ли эта функция log нормально вызываться в IE, а использование apply здесь просто для того, чтобы показать ее? И из связанного вопроса я предполагаю, что это не удастся, если консоль IE будет закрыта, когда она запустится, поэтому log не будет работать даже после открытия консоли, правильно? Если это не так, может кто-нибудь объяснить, как это работает?

Эта статья ycombinator кажется актуальной. Говорят ли они о том же IE-поведении, что и вопрос, связанный выше?

Function.prototype.apply.apply(console.log, [console, arguments]);

Работает как на IE9, сломанной console.log, так и на обычной консоли .log от других поставщиков. Такой же взлом, как использование Array.prototype.slice для преобразования аргументов в реальный массив.

Это хорошо работает на моей консоли Chrome.

function echo(){
  Function.prototype.apply.apply(console.log, [console, arguments]);
}

Упрощенная:

function echo(){
  Function.apply.call(console.log, console, arguments);
}

Добавьте чек и возврат:

function echo(){
  return window.console && console.log &&
         Function.apply.call(console.log, console, arguments);
}

Приведенный выше пример выглядит адекватным мне. Тем не менее, у меня нет IE на руках, чтобы проверить его. Это разумный подход для безопасной упаковки console.log?


Другие вопросы

Следуя приведенной ниже ссылке в навигация, мы видим код:

Function.prototype.call.call(console.log, console,
    Array.prototype.slice.call(arguments));

Какова цель преобразования arguments в массив в этом случае? Думаю, в каком-то браузере это не сработает, если вы этого не сделаете? И, в отличие от оперного поведения и беспроблемных браузеров, не должно быть что-то вроде этого в значительной степени работать и для любого другого браузера? И prototype служит цели в приведенных выше примерах, или мы просто педантичны... Function.call.call или Object.call.call или, если это важно, isNaN.call.call, похоже, работают так же хорошо, как и Function.prototype.call.call.

Ответ 1

Может ли эта функция журнала нормально вызываться в IE, а использование apply здесь просто для того, чтобы показать ее?

Да и да. Этот конкретный пример был нацелен прямо на часть "является ли это реальной функцией" связанного вопроса.

И я полагаю из связанного вопроса, что это не удастся, если консоль IE будет закрыта при ее запуске, поэтому журнал не будет работать даже после того, как консоль откроется, правильно?

Правильно. Как пояснялось в моем ответе на этот вопрос, объект console не отображается до тех пор, пока инструменты разработчика не откроются для определенной вкладки. Большинство разработчиков используют консольную прокладку, и в этом случае подход Function#bind становится немного устаревшим, поскольку вы также можете использовать метод Function#apply.apply.

Какова цель преобразования аргументов в массив в этом случае?

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

И прототип служит цели в приведенных выше примерах, или мы просто педантичны...

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

Ответ 2

Проблема с обертками заключается в том, что они будут обфускать имя файла и номер строки источника сообщения журнала.

Простая настройка IE7 и ниже, которая сохраняет нумерацию строк для других браузеров:

/* console shim*/
(function () {
    var f = function () {};
    if (!window.console) {
        window.console = {
            log:f, info:f, warn:f, debug:f, error:f
        };
    }
}());

Ответ 3

Извините, в моем посте была ошибка. Не знаю, как я это пропустил.

PROPER способ создать глобальный объект консоли, если он не существует:

if (typeof console === "undefined"){
    console={};
    console.log = function(){
        return;
    }
}

Ответ 4

Мне нравится использовать:

'console' in window && console.log("Boom!");

Он работает во всех браузерах и легко понять.

Ответ 6

Попробуйте использовать фрагмент кода ниже... (это мой предпочтительный подход, потому что он делает вас независимым от window.console)

var logger = (function (c) {
    "use strict";
    var m = {
        log: function (a, t) {
            if (!c) { return; /* return or call your custom function here */ }
            var l = c.log,
                f = t === undefined ? l : (this.__dict__[t] || l);
            f.apply(c, a)
        },
        __dict__: {
            "trace": c.trace,
            "debug": c.debug,
            "info": c.info,
            "warn": c.warn,
            "error": c.error
        }
    };

    return {
        trace: function () { m.log(arguments, "trace"); },
        debug: function () { m.log(arguments, "debug"); },
        info: function () { m.log(arguments, "info"); },
        warn: function () { m.log(arguments, "warn"); },
        error: function () { m.log(arguments, "error"); },
        log: function () { m.log(arguments, undefined); }
    };
}(window.console))

Итак, вы можете попробовать это в своем коде и увидеть результат

logger.info("Hello");
logger.trace("Hello");
logger.debug("Hello");
logger.warn("Hello");
logger.error("Hello");
logger.log("Hello");

Ответ 7

Как небольшая вариация ответа Криса, просто определите "журнал" как свойство "консоли" с пустой функцией:

if (typeof console === "undefined") {
    console = {
        log: function () {
            return;
        } 
   };
}

Ответ 8

Paul Irish имеет приятную световую упаковку/замену для console.log().

http://paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/

Преимущества:

  • Предотвращать ошибки, если консоль не находится вокруг (то есть IE)
  • Сохраняет историю журналов, поэтому вы можете смотреть в прошлом, если ваша консоль добавляется впоследствии (например, firebug lite).
  • Легкий и простой.
  • Очень быстрый тип - log() или window.log().

Ответ 9

Использовать утешение

Моя смехотворно перегруженная консоль:

  • предотвращает ошибки, если нет консоли
  • предотвращает ведение журнала в процессе производства, если вы оставили операторы console.log в своем коде
  • поддерживает console.error, console.group и все такие другие методы
  • по-прежнему дает вам обратные выходы для операторов журнала

Это потрясающе.

Но на самом деле вам не следует оставлять console утверждения, лежащие в вашем коде.

Вот и дрожь! Представление: Consolation.js

Ответ 10

CoffeeScript:

empty_function = ->
  return
if !window.console?
  window.console = {}
  for fn in ['log', 'info', 'warn', 'debug', 'error']
    if (typeof window.console[fn] isnt 'function')
      window.console[fn] = empty_function

JS:

(function() {
  var empty_function, fn, i, len, ref;

  empty_function = function() {};

  if (window.console == null) {
    window.console = {};
    ref = ['log', 'info', 'warn', 'debug', 'error'];
    for (i = 0, len = ref.length; i < len; i++) {
      fn = ref[i];
      if (typeof window.console[fn] !== 'function') {
        window.console[fn] = empty_function;
      }
    }
  }

}).call(this);

Ответ 11

Мое решение немного другое. Я создаю стандартный ярлык для всех вызовов console.log: В моем случае kag (что бы я ни хотел сообщить в консоли).

Я тестирую IE, если IE отправил результаты в окно предупреждения. Если Chrome отображается в консоли. Это также означает, что IE всегда будет работать даже в консоли закрыт:

код:

var iever = getInternetExplorerVersion();
if(iever>-1){
function kag(params){
    alert(params);
}
} else {
var kag = console.log.bind(console, "REPORT: ");
}

function getInternetExplorerVersion() {
var rv = -1;
if (navigator.appName == 'Microsoft Internet Explorer') {
var ua = navigator.userAgent;
var re  = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
if (re.exec(ua) != null){
  rv = parseFloat( RegExp.$1 );
}
}
return rv;
}