Почему не работает псевдоним JavaScript? - PullRequest
21 голосов
/ 16 апреля 2010

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

var log;

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

Я получаю "Uncaught TypeError: Illegal Invocation" в Chrome = /

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

Ответы [ 5 ]

27 голосов
/ 16 апреля 2010

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

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.

6 голосов
/ 21 июня 2012

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

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

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

Работает с инструментами Firebug и Chrome Dev и не выдает ошибок, когда консоль недоступна. И - что наиболее важно - показывает правильный файл и номер строки.

2 голосов
/ 16 апреля 2010

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

log("hi");

Пока это происходит:

log.call(console, "hi");

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

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

Обновление

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

var log = (function (console) {
    return console
        ? function () { console.log.apply(console, arguments); }
        : function () {}
})(window.console);
1 голос
/ 04 сентября 2010

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

Обратите внимание, что мы не устанавливаем контекст, который был первоначальной проблемой, но, как оказалось, 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");
}
0 голосов
/ 22 июня 2012

Я сделал это

var log;

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