Ist es möglich, die toString () - Funktion von JavaScript zu überschreiben, um eine aussagekräftige Ausgabe für das Debuggen bereitzustellen?

114

Wenn ich console.log()ein Objekt in meinem JavaScript-Programm habe, sehe ich nur die Ausgabe [object Object], was nicht sehr hilfreich ist, um herauszufinden, um welches Objekt (oder sogar welchen Objekttyp) es sich handelt.

In C # bin ich es gewohnt, zu überschreiben ToString(), um die Debugger-Darstellung eines Objekts anpassen zu können. Gibt es etwas Ähnliches, das ich in JavaScript tun kann?

devios1
quelle
2
Ich finde, dass die Ausgabe die zuverlässigste Methode ist, um Ihnen zu sagen, was eine Variable enthält (oder zumindest besser als typeof).
Alex

Antworten:

102

Sie können auch toStringin Javascript überschreiben . Siehe Beispiel:

function Foo() 
{
}

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

var f = new Foo();
alert(f);  // popup displays [object Foo]

In dieser Diskussion erfahren Sie, wie Sie den Objekttypnamen in JavaScript bestimmen.

Michael Spector
quelle
8
Während es wahr ist, zeigt die Alarmfunktion den Rückgabewert der Funktion an, die die Prototyp- toStringEigenschaft überschreibt , und Object.prototype.toString.call(f)wird weiterhin angezeigt [object Object].
Frederik Krautwald
14
'Object.prototype.toString.call (f) zeigt weiterhin [Objekt Objekt] an.' Ja, denn das ist eine völlig andere Funktion als 'Foo.prototype.toString', lol.
Triynko
5
Falls jemand wie ich hier landet, können Sie Sybmol.toStringTag in ES6 verwenden, um das Verhalten von Object.prototype.toString.call anzupassen. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
TLadd
31

Erste Überschreibung toStringfür Ihr Objekt oder den Prototyp:

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

var foo = new Foo();

Konvertieren Sie dann in eine Zeichenfolge, um die Zeichenfolgendarstellung des Objekts anzuzeigen:

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

Wenn Ihnen die zusätzliche Eingabe nicht gefällt, können Sie eine Funktion erstellen, die Zeichenfolgendarstellungen ihrer Argumente in der Konsole protokolliert:

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

Verwendung:

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

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

Aktualisieren

E2015 bietet eine viel schönere Syntax für dieses Zeug, aber Sie müssen einen Transpiler wie Babel verwenden :

// 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
quelle
5
console.log ('' + foo); Dies war das Problem, bei dem ich keine toString-Implementierung sah, bis ich zu Ihrer Antwort kam.
Ahmadalibaloch
13

Eine einfache Möglichkeit, eine debuggbare Ausgabe in Browser JS zu erhalten, besteht darin, das Objekt einfach in JSON zu serialisieren. So könnten Sie einen Anruf tätigen wie

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

So zum Beispiel alert("Blah! " + JSON.stringify({key: "value"}));erzeugt eine Benachrichtigung mit dem TextBlah! {"key":"value"}

Paul V.
quelle
Das ist ziemlich praktisch. Die Ausgabe kann, wie ich mir vorstellen kann, etwas riesig sein, funktioniert aber zur Not!
Devios1
@dev Handy, überschreibt jedoch nicht toString ().
Dan Dascalescu
10

Wenn Sie Node verwenden, ist dies möglicherweise eine Überlegung wert 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 );

Dies ergibt:

{ #Point 1,2 }

Während die Version ohne Inspektion druckt:

{ x: 1, y: 2 }
SystematicFrank
quelle
6

Überschreiben Sie einfach die toString()Methode.

Einfaches Beispiel:

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

Es ist sogar noch besser, wenn Sie einen neuen Typ definieren:

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
quelle
9
Dieser Code löst das console.log-Problem des OP nicht, zumindest nicht in node.js v0.10.*oder Chrome Version 32.0.1700.102. Während der direkte Aufruf von toString (lame) oder die Verwendung von Type Coercion (lamer) damit funktioniert, verwendet die Konsole [/ info | log /] den alten Pre-Mod toString.
James_womack
1
Es ist jetzt 2019 und sowohl NodeJS als auch Chrome Pretty-Print-Objekte für sich. Daher ist Zwang (wenn Sie das Objekt einer Zeichenfolge hinzufügen) der einzige Anwendungsfall, bei dem Sie diese Frage meiner Meinung nach googeln würden.
Klesun
6

Wenn das Objekt von Ihnen selbst definiert wurde, können Sie jederzeit eine toString-Überschreibung hinzufügen.

//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);

Gehacktes Kind
quelle
5

Mit Vorlagenliteralen :

class Foo {
  toString() {
     return 'I am foo';
  }
}

const foo = new Foo();
console.log(`${foo}`); // 'I am foo'
Sami
quelle
3

Fügen Sie dem benutzerdefinierten Objekt oder der benutzerdefinierten Klasse die Eigenschaft 'Symbol.toStringTag' hinzu .

Der ihm zugewiesene Zeichenfolgenwert ist die Standardzeichenfolgenbeschreibung, da die Object.prototype.toString()Methode intern auf sie zugreift.

Beispielsweise:

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

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

Für einige Javascript-Typen wie Maps und Promises ist ein integriertes toStringTagSymbol definiert

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

Da Symbol.toStringTages sich um ein bekanntes Symbol handelt , können wir darauf verweisen und überprüfen, ob die oben genannten Typen die Eigenschaft Symbol.toStringTag haben.

new Map()[Symbol.toStringTag] // 'Map'
Promise.resolve()[Symbol.toStringTag] // 'Promise'
Danield
quelle
Ist dies zusammen mit dem toString()direkten Überschreiben der einzige Weg, um dies zu erreichen function MyObj() {} Object.prototype.toString.call(new MyObj()) // "[object MyObj]"?
Tonix
1
@tonix - Ich denke schon ... Wenn es einen anderen Weg gibt, lass es mich wissen;)
Danield
0

Mit dem Chrome-Konsolenprotokoll können Sie das Objekt überprüfen.

Tomconte
quelle
Ja, das stimmt, wenn ich nur das Objekt ausgebe, was praktisch ist. Manchmal möchte ich es jedoch nur als Teil einer Zeichenfolge ausgeben, die ich möglicherweise verwende, um andere Daten zu enthalten, und es wäre schön, wenn ich dieses Formular auf irgendeine Weise anpassen könnte.
Devios1
6
Ich habe gerade festgestellt, dass Sie zusätzliche Argumente in einem console.log verwenden können, um Objekte inline mit einer Zeichenfolge auszugeben : console.log("this is my object:", obj).
Devios1
0

-Dieser Vorgang nimmt viel Zeit in Anspruch und wird laut Mozilla-Dokumenten nicht empfohlen: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

- Offensichtlich veralten moderne Browser .prototype und ECMA6 spezifiziert stattdessen die Verwendung von Proper__proto__.

Wenn Sie beispielsweise Ihre eigene Objekt- Geoposition definieren , sollten Sie die Eigenschaft __proto__ anstelle von .prototype aufrufen :

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
quelle
0

Hier ist ein Beispiel zum Stringifizieren eines Map-Objekts:

  Map.prototype.toString = function() {

    let result = {};

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

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

Sie können allen benutzerdefinierten Objekten ihre eigenen toString-Methoden zuweisen oder eine allgemeine Methode schreiben, die Sie für das Objekt aufrufen können, das Sie betrachten.

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
quelle
-1

toString()Wenn Sie die Prototype JavaScript Library einschließen , können Sie Object.inspect()eine viel nützlichere Darstellung erhalten, anstatt sie zu überschreiben .

Die beliebtesten Frameworks enthalten etwas Ähnliches.

Codelahoma
quelle
-1

Sie können in JS erweitern oder überschreiben

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

ch2o
quelle
Wie fügt dies den Antworten von 2011 etwas hinzu, das dieselbe Lösung bietet?
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
quelle