【问题标题】:TypeScript toString ignored by debugger调试器忽略 TypeScript toString
【发布时间】:2018-09-14 11:34:09
【问题描述】:

作为对此的后续问题: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 似乎被忽略并显示默认显示。我针对 Google Chrome 的调试器(悬停在变量上)和 VS Code 的调试器(都悬停在变量上,并在“locals”选项卡中查看)进行了测试。

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

注意:我用 lambda 版本的 toString 没关系,结果是一样的。

【问题讨论】:

  • @wonea,请查看我发布的答案。不是一个确切的解决方案,而是分享我上次尝试获得类似工作的发现
  • 为了我的需要,我利用了这样一个事实,即 Chrome 的 DevTools 中的对象在缩写时(悬停或折叠在控制台中)具有按照它们在代码中找到的顺序列出的属性(或者如果您使用超类,则有继承权)。这意味着将关键信息(即“toString”类型的信息)作为类中定义的第一个属性——这样你就可以选择你所看到的。

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


【解决方案1】:

我在 Chrome DevTools 中发现了如何做到这一点(仍然没有 VSCode 的解决方案):

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

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

完成此操作后,您可以在代码中创建自定义格式化程序,然后将其分配给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 找到(我的代码只是该文章中发布的示例之一的略微修改版本)。

【讨论】:

    【解决方案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 代码以更改行为并显示不同的文本。

    • 我从来没有一个清晰的方法来实际了解可以做什么以及如何制定适当的解决方案,所以就让它自己留在那里。

    简而言之,这是可能的,但需要付出体面的努力才能使其发挥作用

    【讨论】:

      【解决方案3】:

      您能否提供一个示例,您真正希望在调试器的哪个位置看到什么?

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

      【讨论】:

      • 来自 c# world 的示例:blogs.msdn.microsoft.com/soultech/2011/04/05/…,将第一个“快速观看”图像与第二个图像进行比较。
      • 至于您的第二条评论,在 toString() 中修改状态或进行无限循环是一件可怕的事情。在 c# + VS 世界中,调试器正在执行 toString 并且已经执行了多年(我想它确实有一些超时,以防 toString 花费太长时间)。
      猜你喜欢
      • 1970-01-01
      • 2014-04-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多