Que fait cette déclaration? Console.log.bind (console)

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:

  1. Ce qui précède: vous utilisez un moteur JavaScript qui ne fait pas de console.log une fonction réelle.

  2. 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"], …