เป็นไปได้ไหมที่จะแทนที่ฟังก์ชัน toString () ของ JavaScript เพื่อจัดเตรียมเอาต์พุตที่มีความหมายสำหรับการดีบัก


116

เมื่อฉันconsole.log()เป็นออบเจ็กต์ในโปรแกรม JavaScript ฉันเพิ่งเห็นผลลัพธ์[object Object]ซึ่งไม่ค่อยมีประโยชน์ในการหาว่าวัตถุ (หรือแม้แต่ประเภทของวัตถุ) นั้นเป็นอย่างไร

ใน C # ฉันใช้เพื่อแทนที่ToString()เพื่อให้สามารถปรับแต่งการแสดงดีบักเกอร์ของวัตถุได้ มีอะไรที่คล้ายกันที่ฉันสามารถทำได้ใน JavaScript หรือไม่?


2
ฉันพบว่าผลลัพธ์เป็นวิธีที่น่าเชื่อถือที่สุดในการบอกคุณว่าตัวแปรมีอะไรบ้าง (หรืออย่างน้อยก็ดีกว่าtypeof)
alex

คำตอบ:


103

คุณสามารถแทนที่toStringใน Javascript ได้เช่นกัน ดูตัวอย่าง:

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]

ดูนี้การอภิปรายเกี่ยวกับวิธีการตรวจสอบชื่อชนิดของวัตถุใน JavaScript


8
แม้ว่าจะเป็นความจริง แต่ฟังก์ชันการแจ้งเตือนจะแสดงค่าที่ส่งคืนของฟังก์ชันที่แทนที่toStringคุณสมบัติต้นแบบแต่Object.prototype.toString.call(f)จะยังคงแสดง[object Object]อยู่
Frederik Krautwald

14
'Object.prototype.toString.call (f) จะยังคงแสดง [object Object]' ใช่เพราะมันเป็นฟังก์ชันที่แตกต่างจาก 'Foo.prototype.toString' อย่างสิ้นเชิงฮ่า ๆ
Triynko

5
ในกรณีที่มีคนอื่นเช่นฉันมาพบที่นี่คุณสามารถใช้ Sybmol.toStringTag ใน ES6 เพื่อปรับแต่งพฤติกรรม Object.prototype.toString.call developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
TLadd

32

ก่อนอื่นแทนที่toStringวัตถุของคุณหรือต้นแบบ:

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

var foo = new Foo();

จากนั้นแปลงเป็นสตริงเพื่อดูการแสดงสตริงของวัตถุ:

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

หากคุณไม่ชอบการพิมพ์พิเศษคุณสามารถสร้างฟังก์ชันที่บันทึกการแสดงสตริงของอาร์กิวเมนต์ไปยังคอนโซล:

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

การใช้งาน:

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

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

ปรับปรุง

E2015 มีไวยากรณ์ที่ดีกว่ามากสำหรับสิ่งนี้ แต่คุณจะต้องใช้ทรานสไพเลอร์เช่น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 ('' + foo); นี่เป็นปัญหาที่ฉันไม่เห็นการใช้งาน toString ใด ๆ จนกว่าฉันจะได้รับคำตอบจากคุณ
ahmadalibaloch

13

วิธีง่ายๆในการรับเอาต์พุตที่ดีบักได้ในเบราว์เซอร์ JS คือเพียงแค่ทำให้วัตถุเป็นอนุกรมกับ JSON ดังนั้นคุณสามารถโทรออกได้

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

ตัวอย่างเช่นalert("Blah! " + JSON.stringify({key: "value"}));สร้างการแจ้งเตือนพร้อมข้อความBlah! {"key":"value"}


ที่มีประโยชน์มาก ผลลัพธ์อาจจะใหญ่ไปหน่อยที่ฉันคิด แต่ใช้งานได้ดี!
devios1

@dev Handy แต่ไม่แทนที่ toString ()
Dan Dascalescu

10

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

สิ่งนี้จะให้ผล:

{ #Point 1,2 }

ในขณะที่เวอร์ชันที่ไม่มีการตรวจสอบการพิมพ์:

{ x: 1, y: 2 }

6

เพียงแค่ลบล้างไฟล์ toString()วิธีการ

ตัวอย่างง่ายๆ:

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

จะดียิ่งขึ้นเมื่อคุณกำหนดประเภทใหม่:

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
รหัสนี้ไม่ได้แก้ปัญหา console.log ของ OP อย่างน้อยไม่ได้อยู่ใน Node.js v0.10.*หรือ Version 32.0.1700.102Chrome ในขณะที่เรียก toString โดยตรง (ง่อย) หรือใช้ type coercion (lamer) จะทำงานกับสิ่งนี้ console [/ info | log /] ใช้เพื่อ pre-mod toString แบบเก่า
james_womack

1
ตอนนี้เป็นปี 2019 และทั้ง nodejs และ chrome พรินต์วัตถุสวย ๆ ด้วยตัวเองดังนั้นการบีบบังคับ (เมื่อคุณเพิ่มวัตถุลงในสตริง) เป็นกรณีการใช้งานเดียวที่คุณจะใช้ Google คำถามนี้ฉันเชื่อ
Klesun

6

หากวัตถุถูกกำหนดด้วยตัวคุณเองคุณสามารถเพิ่ม toString override ได้ตลอดเวลา

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



3

เพิ่ม'Symbol.toStringTag'คุณสมบัติให้กับวัตถุหรือคลาสที่กำหนดเอง

ค่าสตริงที่กำหนดให้จะเป็นคำอธิบายสตริงเริ่มต้นเนื่องจากมีการเข้าถึงภายในโดยไฟล์ Object.prototype.toString()วิธีการ

ตัวอย่างเช่น:

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

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

Javascript บางประเภทเช่น Maps และ Promises มีtoStringTagสัญลักษณ์ในตัวที่กำหนดไว้

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

เนื่องจากSymbol.toStringTagเป็นสัญลักษณ์ที่รู้จักกันดีเราจึงสามารถอ้างอิงและตรวจสอบได้ว่าประเภทข้างต้นมีคุณสมบัติ Symbol.toStringTag -

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

สิ่งนี้ร่วมกับการลบล้างtoString()วิธีเดียวที่จะบรรลุได้โดยตรงfunction MyObj() {} Object.prototype.toString.call(new MyObj()) // "[object MyObj]"หรือไม่?
tonix

1
@tonix - ฉันคิดอย่างนั้น ... ถ้ามีวิธีอื่นโปรดแจ้งให้เราทราบ;)
Danield

0

บันทึกของคอนโซล Chrome ช่วยให้คุณตรวจสอบวัตถุได้


ใช่นั่นเป็นความจริงถ้าฉันส่งออกเพียงวัตถุซึ่งมีประโยชน์ อย่างไรก็ตามบางครั้งฉันก็แค่ต้องการเอาท์พุทเป็นส่วนหนึ่งของสตริงที่ฉันอาจใช้เพื่อบรรจุข้อมูลอื่น ๆ และคงจะดีถ้าฉันสามารถปรับแต่งฟอร์มนั้นได้ในบางลักษณะ
devios1

6
ฉันเพิ่งค้นพบว่าคุณสามารถใช้การขัดแย้งเพิ่มเติมใน console.log console.log("this is my object:", obj)เพื่อการส่งออกวัตถุใกล้เคียงกับสตริง:
devios1

0

- การดำเนินการนี้ใช้เวลามากในการดำเนินการให้เสร็จสมบูรณ์และไม่ควรใช้งานตามเอกสารของ mozilla: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

- เห็นได้ชัดว่าเบราว์เซอร์สมัยใหม่เลิกใช้ .prototype และ ECMA6 ระบุว่าใช้ Proper__proto__ แทน

ดังนั้นสำหรับตัวอย่างเช่นถ้าคุณกำลังกำหนดวัตถุที่คุณเองgeopositionคุณควรจะเรียก__proto__คุณสมบัติแทน.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

นี่คือตัวอย่างวิธีการผูกวัตถุแผนที่:

  Map.prototype.toString = function() {

    let result = {};

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

    return JSON.stringify(result);
  };

-1

คุณสามารถให้อ็อบเจ็กต์ที่กำหนดเองใด ๆ เมธอด toString ของตัวเองหรือเขียนอ็อบเจ็กต์ทั่วไปที่คุณสามารถเรียกใช้กับอ็อบเจ็กต์ที่คุณกำลังดู -

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

แทนที่จะลบล้างtoString()หากคุณรวมไลบรารี Prototype JavaScriptไว้คุณสามารถใช้Object.inspect()เพื่อรับการแสดงที่มีประโยชน์มากขึ้น

เฟรมเวิร์กที่ได้รับความนิยมส่วนใหญ่มีสิ่งที่คล้ายกัน


-1

คุณสามารถขยายหรือแทนที่ใน JS

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


สิ่งนี้เพิ่มอะไรให้กับคำตอบปี 2011 ที่ให้คำตอบเดียวกันได้อย่างไร
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;
};
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.