是否可以覆盖JavaScript的toString()函数来为调试提供有意义的输出?

时间:2011-06-10 14:08:39

标签: javascript debugging tostring

当我console.log()我的JavaScript程序中的一个对象时,我只看到输出[object Object],这对于确定它是什么对象(甚至是什么类型的对象)并不是很有帮助。 / p>

在C#中,我习惯于覆盖ToString()以便能够自定义对象的调试器表示。我能在JavaScript中做些类似的事情吗?

14 个答案:

答案 0 :(得分:91)

您也可以在Javascript中覆盖toString。见例:

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]

请参阅this有关如何在JavaScript中确定对象类型名称的讨论。

答案 1 :(得分:23)

首先覆盖您的对象或原型的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'

答案 2 :(得分:13)

在浏览器JS中获取可调试输出的简单方法是将对象序列化为JSON。所以你可以像

那样打电话
console.log ("Blah: " + JSON.stringify(object));

因此,举例来说,alert("Blah! " + JSON.stringify({key: "value"}));会生成包含文字Blah! {"key":"value"}

的提醒

答案 3 :(得分: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}"

答案 4 :(得分:6)

如果您使用的是Node,可能值得考虑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 }

虽然没有检查的版本打印:

$body

答案 5 :(得分:5)

如果对象是由您自己定义的,则始终可以添加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);



     

答案 6 :(得分:4)

'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]

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

let p = new Person('Dan');
console.log(Object.prototype.toString.call(p));

诸如Maps和Promises之类的某些Javascript类型具有定义的内置toStringTag符号

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

由于Symbol.toStringTagwell-known symbol,我们可以引用它并验证上面的类型确实具有Symbol.toStringTag属性-

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

答案 7 :(得分:3)

使用template literals

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

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

答案 8 :(得分:1)

Chrome控制台日志允许您检查对象。

答案 9 :(得分:0)

您可以为任何自定义对象提供自己的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);
}

答案 10 :(得分:0)

如果您添加Prototype JavaScript Library,则可以使用toString()来获取更有用的表示,而不是覆盖Object.inspect()

最流行的框架包括类似的内容。

答案 11 :(得分:0)

您可以在JS中扩展或覆盖

POST

答案 12 :(得分:0)

-此操作需要大量时间才能完成    完整,并且根据mozilla docs不鼓励使用: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Object/proto

-显然,现代浏览器已弃用.prototype,而ECMA6指定    而是使用适当的__proto __。

例如,如果要定义自己的对象地理位置,则应调用 __ proto __ 属性,而不是 .prototype

import org.junit.Test;
import org.junit.runner.RunWith;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.test.context.PortTest.RandomPortInitailizer;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.context.support.TestPropertySourceUtils;
import org.springframework.util.SocketUtils;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(initializers = RandomPortInitializer.class)
public class PortTest {
    @Autowired
    private SomeService service;

    @Test
    public void testName() throws Exception {
        System.out.println(this.service);
        assertThat(this.service.toString()).containsOnlyDigits();
    }

    @Configuration
    static class MyConfig {

        @Bean
        public SomeService someService(@Value("${my.random.port}") int port) {
            return new SomeService(port);
        }
    }

    static class SomeService {
        private final int port;

        public SomeService(int port) {
            this.port = port;
        }

        @Override
        public String toString() {
            return String.valueOf(this.port);
        }
    }

    public static class RandomPortInitializer
            implements ApplicationContextInitializer<ConfigurableApplicationContext> {

        @Override
        public void initialize(ConfigurableApplicationContext applicationContext) {
            int randomPort = SocketUtils.findAvailableTcpPort();
            TestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,
                    "my.random.port=" + randomPort);
        }
    }
}

答案 13 :(得分:0)

以下是如何对Map对象进行字符串化的示例:

  Map.prototype.toString = function() {

    let result = {};

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

    return JSON.stringify(result);
  };