È possibile sovrascrivere la funzione toString () di JavaScript per fornire un output significativo per il debug?


115

Quando inserisco console.log()un oggetto nel mio programma JavaScript, vedo solo l'output [object Object], che non è molto utile per capire quale oggetto (o anche quale tipo di oggetto) è.

In C # sono abituato a sovrascrivere ToString()per poter personalizzare la rappresentazione del debugger di un oggetto. C'è qualcosa di simile che posso fare in JavaScript?


2
Trovo che l'output sia il modo più affidabile per dirti cosa contiene una variabile (o almeno meglio di typeof).
alex

Risposte:


103

Puoi eseguire l'override anche toStringin Javascript. Vedi esempio:

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]

Vedi questa discussione su come determinare il nome del tipo di oggetto in JavaScript.


8
Sebbene sia vero, la funzione di avviso visualizzerà il valore restituito dalla funzione che sovrascrive la toStringproprietà del prototipo , Object.prototype.toString.call(f)verrà comunque visualizzato [object Object].
Frederik Krautwald

14
"Object.prototype.toString.call (f) continuerà a visualizzare [Object Object]." Sì, perché è una funzione completamente diversa da "Foo.prototype.toString", lol.
Triynko

5
Nel caso in cui qualcun altro come me finisca qui, puoi usare Sybmol.toStringTag in ES6 per personalizzare il comportamento Object.prototype.toString.call. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
TLadd

32

Primo override toStringper il tuo oggetto o prototipo:

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

var foo = new Foo();

Quindi converti in stringa per vedere la rappresentazione di stringa dell'oggetto:

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

Se non ti piace la digitazione extra, puoi creare una funzione che registra le rappresentazioni di stringa dei suoi argomenti nella console:

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

Uso:

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

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

Aggiornare

E2015 fornisce una sintassi molto più carina per queste cose, ma dovrai usare un transpiler come 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'

6
console.log ('' + pippo); questo era il problema non ho visto alcuna implementazione toString fino a quando non ho raggiunto la tua risposta.
ahmadalibaloch

13

Un modo semplice per ottenere un output di cui eseguire il debug nel JS del browser consiste nel serializzare l'oggetto in JSON. Quindi potresti fare una chiamata come

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

Quindi, ad esempio, alert("Blah! " + JSON.stringify({key: "value"}));produce un avviso con il testoBlah! {"key":"value"}


Questo è abbastanza utile. L'output può essere un po 'enorme immagino, ma funziona in un pizzico!
devios1

@dev Handy, ma non sovrascrive toString ().
Dan Dascalescu

10

Se stai usando Node, potrebbe valere la pena considerare 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 );

Questo produrrà:

{ #Point 1,2 }

Mentre la versione senza ispezione stampa:

{ x: 1, y: 2 }

6

Sovrascrivi il toString()metodo.

Esempio semplice:

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

Funziona ancora meglio quando definisci un nuovo tipo:

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}"

9
Questo codice non risolve il problema console.log dell'OP, almeno non in node.js v0.10.*o Chrome Version 32.0.1700.102. Mentre si chiama toString direttamente (lame) o si usa il tipo coercion (lamer) funzionerà con questo, la console [/ info | log /] usa il vecchio pre-mod toString.
james_womack

1
È il 2019 ora e sia i nodejs che gli oggetti chrome pretty print da soli, quindi la coercizione (quando aggiungi l'oggetto a una stringa) è l'unico caso d'uso in cui potresti cercare su Google questa domanda, credo.
Klesun

6

Se l'oggetto è definito da te, puoi sempre aggiungere un override a 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);


5

Con letterali modello :

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

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

3

Aggiungi la proprietà "Symbol.toStringTag" all'oggetto o alla classe personalizzata.

Il valore di stringa che gli viene assegnato sarà la sua descrizione di stringa predefinita poiché vi si accede internamente dal Object.prototype.toString()metodo.

Per esempio:

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

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

Alcuni tipi di Javascript come Maps e Promises hanno un toStringTagsimbolo integrato definito

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

Poiché Symbol.toStringTagè un simbolo noto , possiamo fare riferimento ad esso e verificare che i tipi precedenti abbiano la proprietà Symbol.toStringTag -

new Map()[Symbol.toStringTag] // 'Map'
Promise.resolve()[Symbol.toStringTag] // 'Promise'

Questo, insieme all'override toString()diretto, è l'unico modo per ottenere risultati function MyObj() {} Object.prototype.toString.call(new MyObj()) // "[object MyObj]"?
tonix

1
@tonix - Penso di sì ... Se c'è un altro modo, fammelo sapere;)
Danield

0

Il registro della console di Chrome ti consente di ispezionare l'oggetto.


Sì, è vero se eseguo l'output solo dell'oggetto, che è utile. Tuttavia a volte voglio solo visualizzarlo come parte di una stringa che potrei usare per contenere altri dati e sarebbe bello se potessi personalizzare quel modulo in qualche modo.
devios1

6
Ho appena scoperto che è possibile utilizzare altri argomenti in una console.log all'uscita oggetti in linea con una stringa: console.log("this is my object:", obj).
devios1

0

-Questa operazione richiede molto tempo per essere completata e il suo utilizzo è sconsigliato secondo i documenti di mozilla: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

-Apparentemente, i browser moderni hanno deprecato .prototype e ECMA6 specifica invece di utilizzare Proper__proto__.

Così, per esempio, se si sta definendo proprio oggetto geoposition si dovrebbe chiamare __proto__ proprietà invece di .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());

0

Ecco un esempio su come stringere un oggetto Map:

  Map.prototype.toString = function() {

    let result = {};

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

    return JSON.stringify(result);
  };

-1

Puoi assegnare a qualsiasi oggetto personalizzato i propri metodi toString o scriverne uno generale che puoi chiamare sull'oggetto che stai guardando-

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

-1

Invece di sovrascrivere toString(), se includi la libreria JavaScript prototipo , puoi usareObject.inspect() per ottenere una rappresentazione molto più utile.

I framework più popolari includono qualcosa di simile.


-1

Puoi estendere o sovrascrivere in JS

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


In che modo questo aggiunge qualcosa alle risposte del 2011 che danno la stessa soluzione?
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;
};
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.