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

Что делает это утверждение? console.log.bind(консоль)

Я использую JavaScript и получаю проблему с утверждением

console.log.bind(console)

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

4b9b3361

Ответ 1

В JavaScript this внутри функции вызов определяется тем, как вызывается функция (для нормальных функций, см. * ниже). Если он вызван как часть выражения, возвращающего свойство объекта (например, foo.bar() вызывает bar() как часть операции поиска свойств, получая его из foo), this устанавливается на объект, из которого свойство было получено во время вызова функции.

Предположим, вам нужна более короткая форма console.log, например f. Вы можете сделать это:

var f = console.log; // <== Suspect!

... но если функция log полагается на this, ссылаясь на объект console во время вызова, то вызов f("Message here") не будет работать, потому что this не будет ссылаться на console.

Function#bind предназначен только для этой ситуации: он позволяет вам создать новую функцию, которая при вызове вызовет оригинал с this, установленным на значение, которое вы даете. Так

var f = console.log.bind(console); // Still suspect, for a different reason

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

За исключением: функции, предоставляемые хостом, такие как console.logalert и getElementById), не обязательно должны быть "реальными" функциями JavaScript (хотя в современных браузерах они, как правило, или, по крайней мере, очень близко), и не обязательно иметь все свои возможности, внедряя bind. Поэтому, если вы получаете сообщение об ошибке в этой строке, возможно, что движок, использующий эту строку, не поддерживает bind в функции console.log.

Итак, что такое "функции, предоставляемые хостом"? Любая функция, явно не определенная в спецификации, как часть JavaScript, язык. Итак, в браузере эти функции, связанные с браузером, такие как alert или console.log и т.д.

Я могу подумать о двух причинах, которые могут вызвать проблемы:

  • Выше: вы используете механизм JavaScript, который не делает console.log реальной функцией.

  • Вы используете строку выше в IE с закрытыми инструментами Dev. В IE, когда инструменты dev не открыты, объект console не определен, и поэтому строка будет бросать ReferenceError.

Если конечная цель состоит в том, чтобы получить функцию, которую вы можете вызвать, скажем f("Message here"), для console.log, здесь, как вы можете сделать это, имея дело с обоими # 1 и # 2 выше:

function f(item) {
    if (typeof console != "undefined" && console.log) {
        console.log(item);
    }
}

Это позволяет вам указывать только один элемент, тогда как console.log позволяет вам указывать несколько элементов (console.log("this", "that", "and the other")), но если console.log может не быть реальной функцией JavaScript, то у него может не быть Function#apply, что делает его очень сложно обернуть.

Теперь, если вам не нужно получать тот же результат, который вы получили бы от console.log("this", "that", "and the other"), пока вы можете видеть, что там, просто используйте console.log(arguments); (arguments - это встроенный идентификатор для всех аргументы передаются в функцию). Но если вы хотите реплицировать точный результат, вы в итоге делаете что-то вроде этого:

function f() {
    var a = arguments;

    if (typeof console != "undefined" && console.log) {
        if (console.log.apply) {
            // It has Function#apply, use it
            console.log.apply(console, arguments);
        } else {
            // Ugh, no Function#apply
            switch (a.length) {
                case 0: console.log(); break;
                case 1: console.log(a[0]); break;
                case 2: console.log(a[0], a[1]); break;
                case 3: console.log(a[0], a[1], a[2]); break;
                case 4: console.log(a[0], a[1], a[2], a[3]); break;
                case 5: console.log(a[0], a[1], a[2], a[3], a[4]); break;
                default:
                    throw "f() only supports up to 5 arguments";
            }
        }
    }
}

... и это просто уродливо.


* ES5 добавили связанные функции, которые являются функциями, которые имеют привязанное к ним значение this через привязку:

// Normal function
function foo() {
    console.log(this.name);
}

// Create a bound function:
var f = foo.bind(someObject);

Не имеет значения, как вы вызываете f, он будет вызывать foo с this, установленным в someObject.

* ES2015 (aka ES6) добавлены функции стрелок. С помощью функций стрелок this устанавливается не, установленным тем, как вызывается функция; вместо этого функция наследует this из контекста, в котором она была создана:

// Whatever `this` is here...
var f = () => {                             // <== Creates an arrow function
    // Is what `this` will be here
};

Функции стрелок действительно удобны, когда вы делаете что-то вроде Array#forEach внутри объектного метода:

this.counter = 0;
this.someArray.forEach(entry => {
    if (entry.has(/* some relevant something */)) {
        ++this.counter;
    }
});

Ответ 2

T.J. Ответ Crowder помог мне объяснить и решить проблему, с которой я столкнулся с перенаправлением вывода console.log, но его решение для случая "no Function # apply" было произвольным ограничением для многих случаев использования.

Я переписал его код, подобный этому, который немного чище и функциональнее:

function f() {
    var a = arguments;

    if (typeof console != "undefined" && console.log) {
        if (console.log.apply) {
            // It has Function#apply, use it
            console.log.apply(console, arguments);
        } else {
            // Ugh, no Function#apply
            var output = '';
            for (i=0;i<arguments.length;i++) {
                output += arguments[i] + ' ';
            }
            console.log(output);
        }
    }
}

console.log разделяет аргументы с пробелом, поэтому я также воспроизвел это здесь. Основное ограничение для этого состоит в том, что он не обрабатывает аргументы, являющиеся объектами. Вы можете при необходимости форматировать их.

Ответ 3

Быстрое обновление по этому вопросу, кажется, что вам больше не нужно привязывать консоль к себе.

Хром начал вносить некоторые глубокие изменения в объект console, который теперь уже привязан к самому себе. https://chromium.googlesource.com/chromium/src.git/+/807ec9550e8a31517966636e6a5b506474ab4ea9

Также кажется, что все другие браузеры пошли по этому пути (проверено на последних версиях Firefox и в Node).

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

Ответ 4

Как указано в других ответах, он дает функцию console.error в качестве обработчика ошибок, а bind(console) заставляет его использовать console в качестве значения this внутри своего тела. В противном случае для this будет установлен глобальный объект (window в браузерах), и вызов не будет выполнен. Хорошо объяснил здесь.

Зачастую это можно увидеть в обработке ошибок Promise (например, в кратком обзоре Angular 2):

System.import("unmarshaller/Unmarshaller.js").then(null, console.error.bind(console));

Оффтоп часть:

Вы можете захотеть создать свой собственный обработчик для предварительной обработки ошибки. В приведенном выше примере console.error печатает некрасиво Error в консоли, потому что SystemJS только говорит, что "Ошибка загрузки Unmarshaller.js". А другая ошибка скрыта в originalErr.

Создайте пользовательский обработчик для развертывания:

function handleError(e) {
    if (e.originalErr)
        throw e.originalErr;
    throw e;
}

System.import("unmarshaller/Unmarshaller.js").then(null, handleError);

Нет необходимости в .bind(), и вы получите первоначально брошенный Error, например:

Ошибка: данный объект не указывает "w: winduptype" и целевой класс не указан:
  [{"w: winduptype": ["FileResource", "ArchiveModel:", "WarArchiveModel"],...