调试器忽略TypeScript toString

时间:2018-04-04 19:25:03

标签: typescript visual-studio-code google-chrome-devtools

作为对此的后续问题:TypeScript override ToString()

我们假设我们有一个Person课程,我们会像这样覆盖toString

class Person {
    constructor(
        public firstName: string,
        public lastName: string
    ) {}

    public toString(): string {
       return this.firstName + ' ' + this.lastName;
    }
} 

因此,正如原始问题中所提到的,这在执行console.log("" + myPerson);时工作正常,但是当在调试器中检查Person的实例时,toString似乎被忽略并且默认显示屏显示。我对谷歌Chrome的调试器(悬停在变量上)和VS Code的调试器(都悬停在变量上,并查看" locals"标签)进行了测试。 / p>

有没有办法让一个或两个调试器尊重toString覆盖?

注意:如果我使用lambda版本的toString并不重要,结果是一样的。

3 个答案:

答案 0 :(得分:2)

所以你的问题几乎与下面的问题相似

How to change string representation of objects in Nodejs debug console view

toString行为不是普通v8引擎调试器API的一部分。

我深入研究了之前发布的链接,发现了一些有趣的指针

  • 从源代码编译NodeJS并观察调试器流量,我意识到有一个customFormatter概念

    setCustomObjectFormatterEnabled: function(enabled)

  • 我能够更改此JavaScript中的一些内容,并使用v8 API调用发回评估的toString

  • 需要修改默认的VS代码以更改行为并显示不同的文本。

  • 我从来没有一个干净的方法来实际看到可以做什么以及如何制定一个合适的解决方案,所以把它留在那里。

所以简而言之,这是可能的,但需要一个体面的努力才能让它发挥作用

答案 1 :(得分:0)

您能举例说明您在调试器的哪个位置实际想看到的内容吗?

如果问题是关于变量范围(即可用的局部变量和全局变量),则调试器不会调用toString(),因为它实际上会在调试脚本中执行代码,这反过来可能会修改状态。想象一下toString()中的无限循环。

答案 2 :(得分:0)

我发现了如何在Chrome DevTools中进行操作(仍然没有VSCode的解决方案):

custom string in dev tools

为此,我们需要在开发工具中启用自定义格式化程序:

  • 打开开发工具
  • 点击右上角的汉堡菜单(三个垂直点)
  • 点击“设置”
  • 在“控制台”下,确保选中“启用自定义格式器”。

完成此操作后,您可以在代码中创建自定义格式化程序,然后将其分配给window["devtoolsFormatters"]

我的示例的完整代码在这里:

class Person {
    constructor(firstName, lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    toString() {
        return `${this.firstName} ${this.lastName}`;
    }
}

Formatter = function (simpleFormatter) {
    this._simpleFormatter = simpleFormatter;
}

Formatter.prototype = {

    header: function (object) {
        if ((object instanceof Node))
            return null;

        var header = new JsonMLElement("span");
        let title = this._simpleFormatter.description(object);
        if (typeof object.toString !== "undefined") {
            title = `${object.toString()} [${this._simpleFormatter.description(object)}]`;
        }
        header.createTextChild(title);
        return header.toJsonML();
    },

    hasBody: function (object) {
        if (object instanceof Array)
            return false;
        return this._simpleFormatter.hasChildren(object);
    },

    body: function (object) {
        var body = new JsonMLElement("ol");
        body.setStyle("list-style-type:none; padding-left: 0px; margin-top: 0px; margin-bottom: 0px; margin-left: 12px");
        var children = this._simpleFormatter.children(object);
        for (var i = 0; i < children.length; ++i) {
            var child = children[i];
            var li = body.createChild("li");
            var objectTag;
            if (typeof child.value === "object")
                objectTag = li.createObjectTag(child.value);
            else
                objectTag = li.createChild("span");

            var nameSpan = objectTag.createChild("span");
            nameSpan.createTextChild(child.key + ": ");
            nameSpan.setStyle("color: rgb(136, 19, 145);");
            if (child.value instanceof Node) {
                var node = child.value;
                objectTag.createTextChild(node.nodeName.toLowerCase());
                if (node.id)
                    objectTag.createTextChild("#" + node.id)
                else
                    objectTag.createTextChild("." + node.className)
            }
            if (typeof child.value !== "object")
                objectTag.createTextChild("" + child.value);

        }
        return body.toJsonML();
    },

    _arrayFormatter: function (array) {
        var j = new JsonMLElement();
        j.createTextChild("[");
        for (var i = 0; i < array.length; ++i) {
            if (i != 0)
                j.createTextChild(", ")
            j.createObjectTag(array[i]);
        }
        j.createTextChild("]");
        return j;
    }
}

JsonMLElement = function (tagName) {
    this._attributes = {};
    this._jsonML = [tagName, this._attributes];
}


JsonMLElement.prototype = {

    createChild: function (tagName) {
        var c = new JsonMLElement(tagName);
        this._jsonML.push(c.toJsonML());
        return c;
    },

    createObjectTag: function (object) {
        var tag = this.createChild("object");
        tag.addAttribute("object", object);
        return tag;
    },

    setStyle: function (style) {
        this._attributes["style"] = style;
    },

    addAttribute: function (key, value) {
        this._attributes[key] = value;
    },

    createTextChild: function (text) {
        this._jsonML.push(text + "");
    },

    toJsonML: function () {
        return this._jsonML;
    }
}

function SimpleFormatter() {

}

SimpleFormatter.prototype = {

    description: function (object) {
        if ((typeof object === "object") && object)
            return object.constructor.name;
        return object;
    },

    hasChildren: function (object) {
        return (typeof object === "object");
    },

    children: function (object) {
        var result = [];
        for (var key in object)
            result.push({ key: key, value: object[key] });
        return result;
    }
}

window["devtoolsFormatters"] = [new Formatter(new SimpleFormatter())];

const p = new Person("Luke", "Skywalker")
console.log(p)

可以找到更多详细信息in this link(我的代码只是该文章中发布的示例之一的略微修改版本)。