Подтвердить что ты не робот

Почему работает сглаживание функций JavaScript?

У меня есть некоторые вызовы функций консоли Firebug, которые я хотел отключить, когда Firebug не был включен, например. консоль не определена. Это отлично работает в IE6 и FF3, но не в Chrome:

var log;

if(console){
  log = console.log;
}else{
  log = function(){ return; }
}

Я получаю сообщение об ошибке "Uncaught TypeError: Illegal Invocation" в Chrome =/

Я прочитал о проблеме здесь, где вам нужно применить контекст, который для меня новый, и я не могу показаться как выполнить описанное выше во всех браузерах...

4b9b3361

Ответ 1

Да, вы должны упорствовать в контексте:

var log;

if (window.console && typeof console.log === "function"){
  // use apply to preserve context and invocations with multiple arguments
  log = function () { console.log.apply(console, arguments); };
} else {
  log = function(){ return; }
}

Что происходит, так это то, что контекст (значение this) неявно задается при вызове функции, например:

var obj = {
  method: function () { return this; }
};

obj.method() === obj; // true

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

Теперь, как в вашем примере, если вы скопируете ссылку этого метода на переменную:

var method = obj.method;
method() === window; // global object

Как вы можете видеть, значение this относится к глобальному объекту.

Итак, чтобы избежать этого неявного поведения, вы можете явно установить контекст с помощью call или apply.

Ответ 2

Проблема с обновением функции (например, console.log) в функции заключается в том, что она теряет свой контекст, то есть не отображает правильный номер строки файла, в который мы помещаем ярлык "log".

Вместо этого я предлагаю что-то вроде этого:

 window.log = ((window.console && window.console.log) ?
              console.log.bind(console) : 
              function(){});

Это работает с инструментами firebug и chrome dev и не вызывает ошибок, когда консоль недоступна. И - самое главное - показывает правильный номер файла и строки.

Ответ 3

Это не работает:

log("hi");

Пока это делает:

log.call(console, "hi");

Очевидно, что вам нужно вызвать функцию aliased с правильным контекстом - как вы сами упомянули.

Я думаю, вам придется использовать оболочку функции (закрытие, которая ссылается на исходный контекст), а не на псевдоним...

Update

Также обратите внимание, что если вы проверите напрямую console, вы можете получить ошибку во время выполнения, когда переменная не существует. Вам лучше проверить его явно как window.console. Здесь один из способов реализации условной log оболочки:

var log = (function (console) {
    return console
        ? function () { console.log.apply(console, arguments); }
        : function () {}
})(window.console);

Ответ 4

Это решение изменяет предыдущий и отличный ответ от CMS для работы с IE8. Перед выполнением этого действия вам нужно открыть консоль IE8 (нажмите F12). (Если вы забудете, вам нужно полностью выйти из IE8 и начать снова, потому что даже если консоль существует, IE8 не будет впоследствии создавать консольный объект.)

Обратите внимание, что мы не устанавливаем контекст, который был исходной проблемой, но, как оказалось, IE8 не требует этого контекста. (Хорошо, потому что IE8 также не предоставляет метод apply для объекта console.log!).

Этот код работает с последними версиями Chrome, FireFox и MSIE. (Он совместим с MSIE6 и не вызывает ошибку.)

if((typeof console !== "undefined") && ((typeof console.log) !== "undefined"))
{
  if ((typeof console.log.apply !== "undefined"))
  {
    log = function() { console.log.apply(console,arguments) };
  }
  else
  {
    log = console.log;
  }
}
else
{
  log = function() {};
  // alert("No debug console");
}

Ответ 5

Я сделал это

var log;

log = function() {
  if ((window.console != null) && (window.console.log.apply != null)) {
    return console.log.apply(console, arguments);
  } else {
    return function() {};
  }
};