2012-03-09 3 views
21

Это просто из любопытства, но у любого из вас есть идея, почему этот код не будет работать?Почему не работает console.log при передаче в качестве параметра forEach?

[1, 2, 3, 4, 5].forEach(console.log); 

// Prints 'Uncaught TypeError: Illegal invocation' in Chrome 

С другой стороны, это, кажется, работает нормально:

[1, 2, 3, 4, 5].forEach(function(n) { console.log(n) }); 

Так что ...?

+4

У вас неправильный 'this'. – SLaks

+0

Действительно. Ответь сам, я такой идиот. –

+0

Можно ли просто удалить? На самом деле это не так полезно =/ –

ответ

8

На самом деле, как @SLaks отметил, console.log, похоже, использует this внутри и когда она передается в качестве параметра this теперь ссылается на экземпляр массива.

Обойти это просто:

var c = console.log.bind(console); [1,2,3,4,5].forEach(c);

+2

Не работает в узле v6 –

-4

Я не могу сказать, что видел этот синтаксис, но я предполагаю, что журнал ожидает параметр, являющийся сообщением/объектом/etc для входа в консоль.

В первом примере вы просто передаете ссылку на функцию forEach, что прекрасно, если ваша функция не ожидает изменения параметров, которые заставляют функцию вести себя так, как ожидалось. Во втором примере вы проходите e, а затем регистрируете его.

+2

Неверно; 'forEach' передает параметр. – SLaks

+0

Точка, которую я пыталась сделать, состоит в том, что параметр должен быть передан в console.log, т. Е. Console.log (_e_) – thescientist

+1

Да, и это именно то, что происходит. Нет никакой разницы между функцией из выражения функции и функцией из свойства. – SLaks

11

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

[1,2,3,4,5].forEach(console.log.bind(console)); 
+2

отличный ответ, я бы хотел отметить его как принятый, но не могли бы вы объяснить (для тех, кто не знает), что делает ваш код? Если нет, я боюсь, что мне придется принять мою, которая немного более информативна. Спасибо –

+2

Не работает в узле v6: > [1,2,3] .forEach (console.log.bind (консоль)) 1 0 [1, 2, 3] 2 1 [1, 2, 3 ] 3 2 [1, 2, 3] –

+0

По-прежнему отсутствует в узле v7. Я бы избегал этого решения, если вы хотите просто зарегистрировать элементы массива. Этот ответ применяет «console.log» к трем параметрам обратного вызова и выводит очень грязный и нежелательный результат. Вероятно, он работал, когда был написан ответ, но только потому, что конкретная реализация JavaScript была неправильной, ИМХО. В эти дни обратный вызов принимает три параметра. –

21

Стоит отметить, что есть разница в поведении при осуществлении console.log. В узле v0.10.19 вы не получите ошибку; вы просто увидите:

> [1,2,3,4,5].forEach(console.log); 
1 0 [ 1, 2, 3, 4, 5 ] 
2 1 [ 1, 2, 3, 4, 5 ] 
3 2 [ 1, 2, 3, 4, 5 ] 
4 3 [ 1, 2, 3, 4, 5 ] 
5 4 [ 1, 2, 3, 4, 5 ] 

Это происходит потому, что обратный вызов forEach является функция трехпараметрическая принимает значение, индекс, а сам массив. Функция console.log видит эти три параметра и послушно регистрирует их.

Под консоли браузера Chrome, однако, вы получите

> [1,2,3,4,5].forEach(console.log); 
TypeError: Illegal invocation 

и в этом случае, bindбудет работа:

> [1,2,3,4,5].forEach(console.log.bind(console)); 
1 0 [ 1, 2, 3, 4, 5 ] 
2 1 [ 1, 2, 3, 4, 5 ] 
3 2 [ 1, 2, 3, 4, 5 ] 
4 3 [ 1, 2, 3, 4, 5 ] 
5 4 [ 1, 2, 3, 4, 5 ] 

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

> [1,2,3,4,5].forEach(console.log, console) 
1 0 [ 1, 2, 3, 4, 5 ] 
2 1 [ 1, 2, 3, 4, 5 ] 
3 2 [ 1, 2, 3, 4, 5 ] 
4 3 [ 1, 2, 3, 4, 5 ] 
5 4 [ 1, 2, 3, 4, 5 ] 

, который работает на консоли Chrome и узле для меня. Конечно, я уверен, что вы хотите всего значения, так что я боюсь, что самое лучшее решение, на самом деле:

> [1,2,3,4,5].forEach(function (e) {console.log(e)}); 
1 
2 
3 
4 
5 

ли поведение узла является ошибкой, или он просто использует в своих интересах факт, что console.log не указан ECMA, интересен сам по себе.Но различное поведение и тот факт, что вы должны знать, имеет ли ваш обратный вызов this, является важным и означает, что мы должны вернуться к прямому кодированию, даже если он является подробным благодаря ключевому слову function.

+0

Спасибо за это объяснение. Читатели могут найти следующую ссылку, которая описывает ожидаемые аргументы для Array.prototype.forEach(), и аргументы, переданные в поставляемый обратный вызов (как вы обсуждали): https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach – arcseldon

+1

Хотя со стрелковыми функциями вы можете использовать: '[1,2,3] .forEach (v => console.log (v)) '. ;-) – RobG

+0

Действительно, я не могу поверить, что до сих пор я использовал выражение функции long-form в качестве аргументов для 'forEach' (и друзей) в начале 2014 года. Однако вскоре он переключился. –

Смежные вопросы