递归函数中的Array.prototype.reduce会产生意外结果

时间:2015-05-16 21:38:18

标签: javascript arrays dom recursion ecmascript-5

我正在尝试编写一个将Array转换为DocumentFragment的函数。数组的每个项都将成为HTMLElement。它的标签名称将是数组项的类名*,其属性将是数组项的属性,其值为字符串。

例如,如果我有这些构造函数:

function Person(name,pets){
        this.name=name;
        this.pets=pets;
    }
function Pet(name){this.name=name;}

这个数据:

var arr=[
        new Person("Bob",[
            new Pet("Sparky"),
            new Pet("Wishbone")
        ]),
        new Person("Mary",[
            new Pet("Maggie"),
            new Pet("Sprinkles")
        ])
    ];

我使用此功能,效果很好:

Array.prototype.toDocFrag=function(){
        return this.reduce(function(docFrag,currentItem){
            elem=document.createElement(currentItem.constructor.name.toLowerCase());
            for (prop in currentItem){
                if (typeof currentItem[prop]==="string") elem.setAttribute(prop,currentItem[prop])
                //if (currentItem[prop] instanceof Array) elem.appendChild(currentItem[prop].toDocFrag())
            }
            docFrag.appendChild(elem)
            return docFrag;
        },document.createDocumentFragment())
    }

如果我运行arr.toDocFrag(),我会按预期获得内容为<person name="Bob"></person><person name="Mary"></person>的docFrag。

但是现在我要做的是让它递归,以便它看到“宠物”并为每个<person>添加另一个DocumentFragment,所以我最终得到了

<person name="Bob">
    <pet name="Sparky"></pet>
    <pet name="Wishbone"></pet>
</person>
<person name="Mary">
    <pet name="Maggie"></pet>
    <pet name="Sprinkles"></pet>
</person> 

取消注释我在代码中注释掉的行,我相信它应该可行。但由于某种原因,arr.toDocFrag()仅返回<pet name="Wishbone"></pet><pet name="Sprinkles"></pet>

我的逻辑出了什么问题?我是否误解了Array.prototype.reduce或递归函数的某些内容?

谢谢!

脚注

*通过类名,我指的是启动实例的构造函数的名称。

1 个答案:

答案 0 :(得分:4)

您的问题是elemimplicitly global variable。这对你的第一个函数无关紧要,但是完全混淆了一个递归函数,其中一个调用覆盖了他的调用者的elem

使用var statement在本地声明变量(prop也缺少变量)。并使用strict mode来获取此类行为的错误。