J'utilise JavaScript et j'ai un problème avec la déclaration
console.log.bind(console)
Veuillez me dire ce que cette déclaration fait réellement. J'ai appliqué plusieurs fois, mais cela n'a rien fait.
En JavaScript, this
dans un appel de fonction est déterminé par la façon dont la fonction est appelée (pour les fonctions normales, voir * ci-dessous). Si on l'appelle comme partie d'une expression récupérant une propriété d'objet (p. foo.bar()
., foo.bar()
bar()
appels foo.bar()
bar()
dans le cadre d'une opération de récupération de propriété l'obtenant de foo
), this
est définie sur l'objet pour lequel la propriété est issue Appel à la fonction.
Supposons que vous vouliez une forme plus courte de console.log
, comme f
. Vous pourriez faire ceci:
var f = console.log; // <== Suspect!
… mais si la fonction de log
repose sur this
réfère à l'objet de la console
pendant l'appel, alors appeler f("Message here")
ne fonctionnera pas, car this
ne fera pas référence à la console
.
Function#bind
est pour cette situation: il vous permet de créer une nouvelle fonction qui, lorsqu'elle est appelée, appellera l'original avec this
ensemble à la valeur que vous donnez. Alors
var f = console.log.bind(console); // Still suspect, for a different reason
… devrait , en théorie, vous donner une fonction, f
, que vous pouvez appeler pour vous connecter à la console.
Sauf : les fonctions fournies par l'hôte comme console.log
(et alert
et getElementById
) ne sont pas nécessaires pour être des fonctions JavaScript "réelles" (même si les navigateurs modernes ont tendance à être, ou au moins très proches) et ne sont pas obligés de Ont toutes leurs fonctionnalités, inculding bind
. Donc, si vous obtenez une erreur sur cette ligne, il se peut que le moteur sur lequel vous utilisez cette ligne ne supporte pas le console.log
sur la fonction console.log
.
Alors, quelles sont les "fonctions fournies par l'hôte"? Toute fonction non définie explicitement dans la spécification faisant partie de JavaScript , la langue. Encore une fois, sur un navigateur qui fonctionne comme un navigateur comme alert
ou console.log
et autres.
Je peux penser à deux raisons pour lesquelles cette ligne pourrait vous poser des problèmes:
Ce qui précède: vous utilisez un moteur JavaScript qui ne fait pas de console.log
une fonction réelle.
Vous utilisez la ligne ci-dessus sur IE avec les Dev Tools fermés. Sur IE lorsque les outils dev ne sont pas ouverts, l'objet console
n'est pas défini, et cette ligne jettera un ReferenceError
.
Si le but final est d'obtenir une fonction que vous pouvez appeler, dites f("Message here")
, pour console.log
, voici comment vous pouvez faire cela en traitant à la fois # 1 et # 2 ci-dessus:
function f(item) { if (typeof console != "undefined" && console.log) { console.log(item); } }
Cela vous permet seulement de donner un élément, tandis que console.log
vous permet de donner plusieurs éléments ( console.log("this", "that", "and the other")
), mais si console.log
peut ne pas être une fonction JavaScript réelle , Alors il se peut qu'il n'y ait pas de Function#apply
, ce qui rend très difficile de l'envelopper.
Maintenant, si vous ne vous souciez pas d'obtenir la même sortie que vous obtenez de console.log("this", "that", "and the other")
tant que vous pouvez voir ce qu'il y a, utilisez simplement console.log(arguments);
(Les arguments
sont l'identifiant intégré pour tous les arguments passés dans une fonction). Mais si vous souhaitez reproduire la sortie exacte, vous finissez par faire quelque chose comme ceci:
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"; } } } }
… et c'est juste laid.
* ES5 a ajouté des fonctions liées , qui sont des fonctions qui leur attachent leur valeur par liaison:
// Normal function function foo() { console.log(this.name); } // Create a bound function: var f = foo.bind(someObject);
Peu importe comment vous appelez f
, il appellera foo
avec this
ensemble sur someObject
.
* ES2015 (aka ES6) a ajouté des fonctions de flèche . Avec les fonctions de flèche, this
n'est pas défini par la façon dont la fonction est appelée; À la place, la fonction l'hérite du contexte dans lequel elle a été créée:
// Whatever `this` is here... var f = () => { // <== Creates an arrow function // Is what `this` will be here };
Les fonctions de flèches sont très utiles lorsque vous faites quelque chose comme Array#forEach
dans une méthode d'objet:
this.counter = 0; this.someArray.forEach(entry => { if (entry.has(/* some relevant something */)) { ++this.counter; } });
La réponse de TJ Crowder m'a aidé à expliquer et à résoudre un problème que j'ai eu avec la console.log
sortie console.log
, mais sa solution pour l'affaire "No Function # apply" semblait arbitrairement limitée pour de nombreux cas d'utilisation.
J'ai réécrit son code comme celui-ci qui est un peu plus propre et plus fonctionnel:
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
sépare les arguments avec un espace, donc j'ai répliqué ici aussi. La principale limitation à cela est qu'il ne gère pas les arguments qui sont des objets. Vous pouvez les distinguer si nécessaire.
J'ose prévoir, c'est ce que beaucoup peuvent rechercher:
Souvent, vous pouvez le voir dans la gestion des erreurs Promise
(par exemple, à partir du démarrage rapide Angular 2):
System.import("unmarshaller/Unmarshaller.js").then(null, console.error.bind(console));
Comme indiqué dans d'autres réponses, il donne la fonction console.error
tant que gestionnaire d'erreur, et bind(console)
fait utiliser la console
comme valeur de this
dans son corps. Sinon, this
serait défini sur un objet global ( window
dans les navigateurs) et l'appel échouerait. Bien expliqué ici .
La partie hors-piste:
Vous voudrez peut-être créer votre propre gestionnaire pour pré-traiter l'erreur. Dans l'exemple ci-dessus, console.error
imprime ugly Error
dans la console car SystemJS
indique seulement "Erreur lors du chargement de Unmarshaller.js" . Et l'autre erreur est cachée dans originalErr
.
Faites en sorte qu'un gestionnaire personnalisé soit déployé:
function handleError(e) { if (e.originalErr) throw e.originalErr; throw e; } System.import("unmarshaller/Unmarshaller.js").then(null, handleError);
Pas besoin de .bind()
, et vous donnera l' Error
initialement lancée, comme:
Erreur: L'objet donné ne spécifie pas "w: winduptype" et aucune classe cible donnée:
[{"W: winduptype": ["FileResource", "ArchiveModel:", "WarArchiveModel"], …