从 javascript 节点对象生成无序列表

发布于 2024-10-09 16:38:53 字数 2505 浏览 0 评论 0 原文

我编写了以下代码,这些代码的目的是从一些javascript Node对象生成一个

<html>

<body>
<div id='content'></div>
<script type='text/javascript'>

            function node(name,parent){
                this.name=name;
                this.parent=parent;
                this.level=function(){
                    if(this.parent==null)
                        return 0;
                    return this.parent.level()+1;                    
                }
                this.childs=new Array();
            }

            //create a rootNode, having no parent
            var rootNode=new node('AAA',null);

            //create node1 and add it to the child of rootNode
            var node1=new node('BBB',rootNode);
            rootNode.childs.push(node1);

            //create node2 and add it to the child of rootNode
            var node2=new node('CCC',rootNode);
            rootNode.childs.push(node2);

            //create node3 and add it to the child of node1
            var node3=new node('DDD',node1);
            node1.childs.push(node3);

            //create node4 and add it to the child of node1
            var node4=new node('EEE',node1);
            node1.childs.push(node4);

            //create node5 and add it to the child of node2
            var node5=new node('FFF',node2);
            node2.childs.push(node5);

            function getTreeHTML(node,html){

                if(node.level()==0)
                    html+='<ul>';

                html+='<li>';
                html+=node.name;
                if(node.childs.length > 0){
                    html+='<ul>';
                    for(var i in node.childs){
                        html+=getTreeHTML(node.childs[i],html);
                    }
                    html+='</ul>';
                }
                html+='</li>';

                if(node.level()==0)
                    html+='</ul>';
                return html;
            }

            var treeHTML=getTreeHTML(rootNode,'');
            document.getElementById('content').innerHTML=treeHTML;
</script>
</body>

</html>

在 rootNode 下,有两个直接子节点,对于这两个子节点,一个其中一个应该有两个 childs 孩子,另一个应该有一个孩子。我怀疑 getTreeHTML() 函数中存在逻辑错误,但我无法弄清楚它是什么,请随意将代码粘贴到 http://htmledit.squarefree.com/,那么你就可以很快明白我的意思。

非常感谢大家。

I have written the following codes, the purpose of these codes is to generate an <ul> from some javascript Node objects:

<html>

<body>
<div id='content'></div>
<script type='text/javascript'>

            function node(name,parent){
                this.name=name;
                this.parent=parent;
                this.level=function(){
                    if(this.parent==null)
                        return 0;
                    return this.parent.level()+1;                    
                }
                this.childs=new Array();
            }

            //create a rootNode, having no parent
            var rootNode=new node('AAA',null);

            //create node1 and add it to the child of rootNode
            var node1=new node('BBB',rootNode);
            rootNode.childs.push(node1);

            //create node2 and add it to the child of rootNode
            var node2=new node('CCC',rootNode);
            rootNode.childs.push(node2);

            //create node3 and add it to the child of node1
            var node3=new node('DDD',node1);
            node1.childs.push(node3);

            //create node4 and add it to the child of node1
            var node4=new node('EEE',node1);
            node1.childs.push(node4);

            //create node5 and add it to the child of node2
            var node5=new node('FFF',node2);
            node2.childs.push(node5);

            function getTreeHTML(node,html){

                if(node.level()==0)
                    html+='<ul>';

                html+='<li>';
                html+=node.name;
                if(node.childs.length > 0){
                    html+='<ul>';
                    for(var i in node.childs){
                        html+=getTreeHTML(node.childs[i],html);
                    }
                    html+='</ul>';
                }
                html+='</li>';

                if(node.level()==0)
                    html+='</ul>';
                return html;
            }

            var treeHTML=getTreeHTML(rootNode,'');
            document.getElementById('content').innerHTML=treeHTML;
</script>
</body>

</html>

Under rootNode, there are two immediate child nodes, for these two child nodes, one of them should have two childs children and another should have one child. I suspect there is a logical bug in the getTreeHTML() function but I just can't figure out what it is, feel free to paste the codes on http://htmledit.squarefree.com/, then you can quickly see what I mean.

Many thanks to you all.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

看透却不说透 2024-10-16 16:38:53

问题就在这里:

html+=getTreeHTML(node.childs[i],html);

您最终添加到 HTML 字符串两次,因为在函数中您附加到传入的 HTML 字符串,但随后您也对其返回的内容使用附加操作。如果您将其更改为其中任何一个,它都可以正常工作:

html=getTreeHTML(node.childs[i],html);
html+=getTreeHTML(node.childs[i],'');

离题:如果您感兴趣的话,一些建议/推荐/观察;以下内容并不重要,只是有帮助:

  1. 如果您在数组中构建一堆字符串,然后使用 join('') ,而不是连接字符串,通常会更快完成后将它们全部组合成一根绳子。
  2. 标准做法(您可以忽略它!)是使像 node 这样的构造函数最初被限制(Node),以将它们与非构造函数区分开来。
  3. 您的每个 node 对象都会获得其自己的 level 函数的副本,这在您的代码中不是必需的。他们都可以共享一个级别功能,如下所示:

    函数节点(名称,父级){
        this.name=名称;
        this.parent=父级;
        this.childs=new Array();
    }
    节点.prototype.level = function() {
        if(this.parent==null)
            返回0;
        返回 this.parent.level()+1;                    
    }
    
  4. 在英语中,“child”的复数是“children”(不规则)。

  5. 使用 for..in 循环遍历数组索引,就像在 for(var i in node.childs){ 中一样,是很微妙的,而且在技术上是不正确的,除非您采取了一些循环中的预防措施;如果你对数组做任何有趣的事情,比如向它们添加更多元数据(数组只是对象,你可以向它们添加任意属性;库有时会向 Array.prototype 添加属性来消除浏览器差异,这会搞乱一个简单的 for..in 循环)。详细信息请参见:的神话与现实for..in
  6. 您可以将 this.childs=new Array(); 编写为 this.childs=[];如果你喜欢;它们具有完全相同的效果。
  7. 无论您将 var 语句放在代码中的什么位置,它都会在函数顶部(或全局作用域的顶部,如果 var是全球性的)。我认为我在这方面有点靠自己,但我不喜欢我的代码对代码维护者有一点误导,所以我总是把 var 放在最上面。更多内容请参见糟糕的误解var。例如:

    //这一系列语句
    做某事();
    doSomethingElse();
    var a = new Foo();
    doAnotherThing();
    
    
    // ...*完全*等同于:
    变量a;
    做某事();
    doSomethingElse();
    a = new Foo();
    doAnotherThing();
    

  8. 推荐 node 上的一个函数,该函数创建一个子节点并将其挂起,这样就可以避免设置 parent 但随后添加子节点的可能性到错误的 childs 数组(或者根本没有添加)。

  9. 使用 null 表示“没有父级”很好,但 undefined 实际上更容易使用。
  10. 您可以使用 JavaScript 强大的 OR 运算符的强大功能(||) 在某些地方。您在 JavaScript 代码中经常会看到这种情况。 if 语句完全没问题,但我认为值得一提,因为这是常见的做法。
  11. 即使没有必要,牙套确实是您的朋友。

将所有这些和一些小事情放在一起:

var rootNode, node1, node2;

function Node(name, parent){
    this.name = name;
    this.parent = parent; // undefined if none
    this.children = [];
}
Node.prototype.level = function(){
    return this.parent ? this.parent.level() + 1 : 0;
};
Node.prototype.addChild = function(name) {
    var child;

    child = new Node(name, this);
    this.children.push(child);
    return child;
};

//create a rootNode, having no parent
rootNode = new Node('AAA');

//create node1 and add it to the child of rootNode
node1 = rootNode.addChild('BBB');

//create node2 and add it to the child of rootNode
node2 = rootNode.addChild('CCC');

//create node3 and add it to the child of node1
node1.addChild('DDD');

//create node4 and add it to the child of node1
node1.addChild('EEE');

//create node5 and add it to the child of node2
node2.addChild('FFF');

function getTreeHTML(node, html) {
    var i;

    html = html || []; // In case they don't give it

    if(node.level()==0) {
        html.push('<ul>');
    }

    html.push('<li>');
    html.push(node.name);
    if (node.children.length > 0) {
        html.push('<ul>');
        for (i = 0; i < node.children.length; ++i) {
            getTreeHTML(node.children[i], html);
        }
        html.push('</ul>');
    }
    html.push('</li>');

    if (node.level() == 0) {
        html.push('</ul>');
    }

    return html;
}

var treeHTML = getTreeHTML(rootNode).join('');
document.getElementById('content').innerHTML=treeHTML;

The problem is here:

html+=getTreeHTML(node.childs[i],html);

You're ending up adding to the HTML string twice, because within the function you append to the HTML string passed in, but then you use an append operation with what it returns as well. If you change it to either of these, it works fine:

html=getTreeHTML(node.childs[i],html);
html+=getTreeHTML(node.childs[i],'');

Off-topic: Some suggestions/recommendations/observations if you're interested; none of the below is meant to be critical, only helpful:

  1. Rather than concatenating strings, it generally works out faster if you build up a bunch of strings in an Array and then use a join('') to put them all together into one string when you're done.
  2. Standard practice (which you're free to ignore!) is to make constructor functions like node initially capped (Node), to differentiate them from non-constructor functions.
  3. Each of your node objects will get its own copy of the level function, which isn't necessary in your code. They can all share one level function, like this:

    function node(name,parent){
        this.name=name;
        this.parent=parent;
        this.childs=new Array();
    }
    node.prototype.level = function() {
        if(this.parent==null)
            return 0;
        return this.parent.level()+1;                    
    }
    
  4. In English, the plural of "child" is "children" (it's irregular).

  5. Using for..in to loop through array indexes, as in your for(var i in node.childs){, is delicate and technically incorrect unless you take a couple of precautions in the loop; it will fail if you do anything interesting with your arrays like add more meta-data to them (arrays are just objects, you can add arbitrary properties to them; and libraries sometimes add properties to Array.prototype to smooth out browser differences, which will muck up a naive for..in loop). Details here: Myths and realities of for..in
  6. You can write this.childs=new Array(); as this.childs=[]; if you like; they have exactly the same effect.
  7. Regardless of where you put your var statement in your code, it takes effect at the top of the function (or the top of the global scope, if the var is global). I think I'm a bit on my own with this, but I don't like having my code be a bit misleading to code maintainers, so I always put the vars up top. More here Poor misunderstood var. So for instance:

    // This series of statements
    doSomething();
    doSomethingElse();
    var a = new Foo();
    doAnotherThing();
    
    
    // ...is *exactly* identical to:
    var a;
    doSomething();
    doSomethingElse();
    a = new Foo();
    doAnotherThing();
    
  8. Recommend a function on node that creates a child and hooks it up, so you avoid the possibility of the parent being set but then the child added to the wrong childs array (or not added at all).

  9. Using null to mean "no parent" is fine, but undefined is actually a bit easier to work with.
  10. You can use the power of JavaScript's Curiously-Powerful OR Operator (||) in some places. You see this a lot in JavaScript code. if statements are totally fine, but I thought it worth mentioning because it's such common practice.
  11. Braces really are your friends, even when they're not necessary.

Taking all of that and a couple of minor things together:

var rootNode, node1, node2;

function Node(name, parent){
    this.name = name;
    this.parent = parent; // undefined if none
    this.children = [];
}
Node.prototype.level = function(){
    return this.parent ? this.parent.level() + 1 : 0;
};
Node.prototype.addChild = function(name) {
    var child;

    child = new Node(name, this);
    this.children.push(child);
    return child;
};

//create a rootNode, having no parent
rootNode = new Node('AAA');

//create node1 and add it to the child of rootNode
node1 = rootNode.addChild('BBB');

//create node2 and add it to the child of rootNode
node2 = rootNode.addChild('CCC');

//create node3 and add it to the child of node1
node1.addChild('DDD');

//create node4 and add it to the child of node1
node1.addChild('EEE');

//create node5 and add it to the child of node2
node2.addChild('FFF');

function getTreeHTML(node, html) {
    var i;

    html = html || []; // In case they don't give it

    if(node.level()==0) {
        html.push('<ul>');
    }

    html.push('<li>');
    html.push(node.name);
    if (node.children.length > 0) {
        html.push('<ul>');
        for (i = 0; i < node.children.length; ++i) {
            getTreeHTML(node.children[i], html);
        }
        html.push('</ul>');
    }
    html.push('</li>');

    if (node.level() == 0) {
        html.push('</ul>');
    }

    return html;
}

var treeHTML = getTreeHTML(rootNode).join('');
document.getElementById('content').innerHTML=treeHTML;
最美不过初阳 2024-10-16 16:38:53

一起删除 html 参数:

function getTreeHTML(node){
    var html = "";
    if(node.level()==0)
        html+='<ul>';

    html+='<li>';
    html+=node.name;
    if(node.childs.length > 0){
        html+='<ul>';
        for(var i in node.childs){
            html+=getTreeHTML(node.childs[i]);
        }
        html+='</ul>';
    }
    html+='</li>';

    if(node.level()==0)
        html+='</ul>';
    return html;
}

Remove the html parameter all together:

function getTreeHTML(node){
    var html = "";
    if(node.level()==0)
        html+='<ul>';

    html+='<li>';
    html+=node.name;
    if(node.childs.length > 0){
        html+='<ul>';
        for(var i in node.childs){
            html+=getTreeHTML(node.childs[i]);
        }
        html+='</ul>';
    }
    html+='</li>';

    if(node.level()==0)
        html+='</ul>';
    return html;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文