Est-il possible de remplacer la fonction toString () de JavaScript pour fournir une sortie significative pour le débogage?

115

Lorsque j'utilise console.log()un objet dans mon programme JavaScript, je vois simplement la sortie [object Object], ce qui n'est pas très utile pour déterminer de quel objet (ou même de quel type d'objet) il s'agit.

En C #, j'ai l'habitude de redéfinir ToString()pour pouvoir personnaliser la représentation du débogueur d'un objet. Puis-je faire quelque chose de similaire en JavaScript?

devios1
la source
2
Je trouve que la sortie est le moyen le plus fiable de vous dire ce qu'une variable contient (ou du moins mieux que typeof).
alex

Réponses:

103

Vous pouvez également remplacer toStringen Javascript. Voir exemple:

function Foo() {}

// toString override added to prototype of Foo class
Foo.prototype.toString = function() {
  return "[object Foo]";
}

var f = new Foo();
console.log("" + f); // console displays [object Foo]

Consultez cette discussion sur la façon de déterminer le nom du type d'objet dans JavaScript.

Michael Spector
la source
8
Tant qu'il est vrai, la fonction d'alerte affichera la valeur de retour de la fonction remplaçant la toStringpropriété prototype , Object.prototype.toString.call(f)sera toujours affichée [object Object].
Frederik Krautwald
14
'Object.prototype.toString.call (f) affichera toujours [object Object].' Ouais, parce que c'est une fonction complètement différente de 'Foo.prototype.toString', lol.
Triynko le
5
Au cas où quelqu'un d'autre comme moi se retrouverait ici, vous pouvez utiliser Sybmol.toStringTag dans ES6 pour personnaliser le comportement d'Object.prototype.toString.call. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
TLadd
32

Premier remplacement toStringpour votre objet ou le prototype:

var Foo = function(){};
Foo.prototype.toString = function(){return 'Pity the Foo';};

var foo = new Foo();

Puis convertissez en chaîne pour voir la représentation sous forme de chaîne de l'objet:

//using JS implicit type conversion
console.log('' + foo);

Si vous n'aimez pas le typage supplémentaire, vous pouvez créer une fonction qui enregistre les représentations sous forme de chaîne de ses arguments dans la console:

var puts = function(){
    var strings = Array.prototype.map.call(arguments, function(obj){
        return '' + obj;
    });
    console.log.apply(console, strings);
};

Usage:

puts(foo)  //logs 'Pity the Foo'

puts(foo, [1,2,3], {a: 2}) //logs 'Pity the Foo 1,2,3 [object Object]'

Mettre à jour

E2015 fournit une syntaxe beaucoup plus agréable pour cela, mais vous devrez utiliser un transpilateur comme Babel :

// override `toString`
class Foo {
  toString(){
    return 'Pity the Foo';
  }
}

const foo = new Foo();

// utility function for printing objects using their `toString` methods
const puts = (...any) => console.log(...any.map(String));

puts(foo); // logs 'Pity the Foo'
Max Heiber
la source
6
console.log ('' + toto); c'était le problème que je n'ai pas vu d'implémentation toString jusqu'à ce que j'aie atteint votre réponse.
ahmadalibaloch
13

Un moyen simple d'obtenir une sortie déboguable dans le navigateur JS consiste simplement à sérialiser l'objet en JSON. Pour que vous puissiez passer un appel comme

console.log ("Blah: " + JSON.stringify(object));

Donc, pour un exemple, alert("Blah! " + JSON.stringify({key: "value"}));produit une alerte avec le texteBlah! {"key":"value"}

Paul V
la source
C'est assez pratique. La sortie peut être un peu énorme j'imagine, mais fonctionne à la rigueur!
devios1
@dev Handy, mais ne remplace pas toString ().
Dan Dascalescu
10

Si vous utilisez Node, cela peut valoir la peine d'être envisagé util.inspect.

var util = require('util')

const Point = {
  x: 1,
  y: 2,
  [util.inspect.custom]: function(depth) { return `{ #Point ${this.x},${this.y} }` }

}

console.log( Point );

Cela donnera:

{ #Point 1,2 }

Alors que la version sans inspecter imprime:

{ x: 1, y: 2 }
SystématiqueFrank
la source
6

Remplacez simplement la toString()méthode.

Exemple simple:

var x = {foo: 1, bar: true, baz: 'quux'};
x.toString(); // returns "[object Object]"
x.toString = function () {
    var s = [];
    for (var k in this) {
        if (this.hasOwnProperty(k)) s.push(k + ':' + this[k]);
    }
    return '{' + s.join() + '}';
};
x.toString(); // returns something more useful

Cela fait encore mieux lorsque vous définissez un nouveau type:

function X()
{
    this.foo = 1;
    this.bar = true;
    this.baz = 'quux';
}

X.prototype.toString = /* same function as before */

new X().toString(); // returns "{foo:1,bar:true,baz:quux}"
Matt Ball
la source
9
Ce code ne résout pas le problème console.log de l'OP, du moins pas dans node.js v0.10.*ou Chrome Version 32.0.1700.102. Tout en appelant directement toString (lame) ou en utilisant la coercition de type (lamer) fonctionnera avec cela, la console [/ info | log /] utilise l'ancien pré-mod toString.
james_womack
1
Nous sommes en 2019 maintenant et les objets nodejs et chrome pretty-print seuls, donc la coercition (lorsque vous ajoutez l'objet à une chaîne) est le seul cas d'utilisation dans lequel vous recherchez cette question sur Google, je crois.
Klesun
6

Si l'objet est défini par vous-même, vous pouvez toujours ajouter un remplacement toString.

//Defined car Object
var car = {
  type: "Fiat",
  model: 500,
  color: "white",
  //.toString() Override
  toString: function() {
    return this.type;
  }
};

//Various ways to test .toString() Override
console.log(car.toString());
console.log(car);
alert(car.toString());
alert(car);

//Defined carPlus Object
var carPlus = {
  type: "Fiat",
  model: 500,
  color: "white",
  //.toString() Override
  toString: function() {
    return 'type: ' + this.type + ', model: ' + this.model + ', color:  ' + this.color;
  }
};

//Various ways to test .toString() Override
console.log(carPlus.toString());
console.log(carPlus);
alert(carPlus.toString());
alert(carPlus);

Enfant piraté
la source
3

Ajoutez la propriété 'Symbol.toStringTag' à l'objet personnalisé ou à la classe.

La valeur de chaîne qui lui est assignée sera sa description de chaîne par défaut car elle est accessible en interne par la Object.prototype.toString()méthode.

Par exemple:

class Person {
  constructor(name) {
    this.name = name
  }
  get [Symbol.toStringTag]() {
    return 'Person';
  }
}

let p = new Person('Dan');
Object.prototype.toString.call(p); // [object Person]

Certains types de Javascript tels que les cartes et les promesses ont un toStringTagsymbole intégré défini

Object.prototype.toString.call(new Map());       // "[object Map]"
Object.prototype.toString.call(Promise.resolve()); // "[object Promise]"

Puisqu'il Symbol.toStringTags'agit d'un symbole bien connu , nous pouvons le référencer et vérifier que les types ci-dessus ont la propriété Symbol.toStringTag -

new Map()[Symbol.toStringTag] // 'Map'
Promise.resolve()[Symbol.toStringTag] // 'Promise'
Danield
la source
Est-ce avec la priorité toString()absolue la seule façon d'y parvenir function MyObj() {} Object.prototype.toString.call(new MyObj()) // "[object MyObj]"?
tonix
1
@tonix - Je pense que oui ... S'il y a un autre moyen, faites-le moi savoir;)
Danield
0

Le journal de la console Chrome vous permet d'inspecter l'objet.

Tomconte
la source
Oui, c'est vrai si je ne produit que l'objet, ce qui est pratique. Cependant, parfois, je veux juste le sortir dans le cadre d'une chaîne que je pourrais utiliser pour contenir d'autres données et ce serait bien si je pouvais personnaliser ce formulaire d'une manière ou d'une autre.
devios1
6
Je viens de découvrir que vous pouvez utiliser des arguments supplémentaires dans un console.log aux objets sortie en ligne avec une chaîne: console.log("this is my object:", obj).
devios1
0

-Cette opération prend beaucoup de temps et son utilisation est déconseillée selon la documentation mozilla: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

-Apparemment, les navigateurs modernes ont désapprouvé le .prototype et ECMA6 spécifie l'utilisation de proper__proto__ à la place.

Ainsi, par exemple, si vous définissez votre propre géoposition d' objet, vous devez appeler la propriété __proto__ au lieu de .prototype :

var  geoposition = {

        lat: window.pos.lat,
        lng: window.pos.lng
    };

geoposition.__proto__.toString = function(){ return "lat: "+this.lat+", lng: "+this.lng }
console.log("Searching nearby donations to: "+geoposition.toString());
jmojico
la source
0

Voici un exemple comment stringifier un objet Map:

  Map.prototype.toString = function() {

    let result = {};

    this.forEach((key, value) => { result[key] = value;});

    return JSON.stringify(result);
  };
Agustí Sánchez
la source
-1

Vous pouvez donner à tous les objets personnalisés leurs propres méthodes toString, ou en écrire une générale que vous pouvez appeler sur l'objet que vous regardez.

Function.prototype.named= function(ns){
    var Rx=  /function\s+([^(\s]+)\s*\(/, tem= this.toString().match(Rx) || "";
    if(tem) return tem[1];
    return 'unnamed constructor'
}

function whatsit(what){
    if(what===undefined)return 'undefined';
    if(what=== null) return 'null object';
    if(what== window) return 'Window object';
    if(what.nodeName){
        return 'html '+what.nodeName;
    }
    try{
        if(typeof what== 'object'){
            return what.constructor.named();
        }
    }
    catch(er){
        return 'Error reading Object constructor';
    }
    var w=typeof what;
    return w.charAt(0).toUpperCase()+w.substring(1);
}
Kennebec
la source
-1

Plutôt que de remplacer toString(), si vous incluez la bibliothèque JavaScript prototype , vous pouvez l'utiliser Object.inspect()pour obtenir une représentation beaucoup plus utile.

Les frameworks les plus populaires incluent quelque chose de similaire.

codélahome
la source
-1

Vous pouvez étendre ou remplacer dans JS

String.prototype.toString = function() {
    return this + "..."
}
document.write("Sergio".toString());

ch2o
la source
En quoi cela ajoute-t-il quelque chose aux réponses de 2011 qui donnent la même solution?
Dan Dascalescu
-3
A simple format Date function using Javascript prototype, it can be used for your purpose

https://gist.github.com/cstipkovic/3983879 :

Date.prototype.formatDate = function (format) {
    var date = this,
        day = date.getDate(),
        month = date.getMonth() + 1,
        year = date.getFullYear(),
        hours = date.getHours(),
        minutes = date.getMinutes(),
        seconds = date.getSeconds();

    if (!format) {
        format = "MM/dd/yyyy";
    }

    format = format.replace("MM", month.toString().replace(/^(\d)$/, '0$1'));

    if (format.indexOf("yyyy") > -1) {
        format = format.replace("yyyy", year.toString());
    } else if (format.indexOf("yy") > -1) {
        format = format.replace("yy", year.toString().substr(2, 2));
    }

    format = format.replace("dd", day.toString().replace(/^(\d)$/, '0$1'));

    if (format.indexOf("t") > -1) {
        if (hours > 11) {
            format = format.replace("t", "pm");
        } else {
            format = format.replace("t", "am");
        }
    }

    if (format.indexOf("HH") > -1) {
        format = format.replace("HH", hours.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("hh") > -1) {
        if (hours > 12) {
            hours -= 12;
        }

        if (hours === 0) {
            hours = 12;
        }
        format = format.replace("hh", hours.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("mm") > -1) {
        format = format.replace("mm", minutes.toString().replace(/^(\d)$/, '0$1'));
    }

    if (format.indexOf("ss") > -1) {
        format = format.replace("ss", seconds.toString().replace(/^(\d)$/, '0$1'));
    }

    return format;
};
aricca
la source