以下代码应该创建一个简单的"树",但它会变成递归和崩溃。
var cnt = 0;
var page = {
properties: {},
folders: [],
items: []
};
function createPage() {
var ret = $.extend({}, page);
ret.cnt = cnt++;
return ret;
}
var tree = createPage();
function addFolders(f, n) {
for (var i = 0; i < n; i++) {
f.push(createPage());
}
}
function createData() {
addFolders(tree.folders, 4);
for (var i = 0; i < tree.folders.length; i++) {
addFolders(tree.folders[i].folders, i);
}
}
createData();
有人可以解释为什么会这样吗?
答案 0 :(得分:2)
folders
数组,导致长度不断增加并且永远不会离开循环。您可以将createPage
功能更改为:
function createPage() {
return {
properties: {},
cnt: cnt++,
folders: [],
items: []
};
}
答案 1 :(得分:2)
$.extend({}, page);
执行page
对象的浅表副本。
var secondPage = $.extend({}, page);
console.log(page === secondPage); // false
console.log(page.folders === secondPage.folders); // true!!
当createData
循环遍历tree.folders
时,它也会对其进行修改,因此每次迭代tree.folders.length
只会增加。
您可以将其他选项传递给$.extend
至do a deep extend $.extend(true, {}, page)
var secondPage = $.extend(true, {}, page);
console.log(page === secondPage); // false
console.log(page.folders === secondPage.folders); // false
答案 2 :(得分:1)
问题:
您的$.extend
没有进行深层复制,因此子文件夹始终是对相同根文件夹的引用。执行此操作var ret = $.extend(true, {}, page);
或直接在createPage()
中使用对象文字。它只是一个浅的副本。不会复制引用两个数组和对象的属性。这些是参考文献。
复制/测试:
将console.log(page.folders.length)
放在createPage()
内。您将看到原始folders
对象的page
发生了变异。好主意让一个计数器在达到100
时会抛出一个错误,以致它无法无限递归。此外,使用开发人员工具在代码运行时逐步执行。
解决方案:
原始外部对象保留在浅层。但你不只是改变外部物体;你正在改变外部对象引用的对象。这就是我在上面展示的deep
选项的原因。因此,当您推送到副本的.folders
时,您将推送到原始文件的.folders
,因为它没有复制它;它为外部副本分配了一个引用。
这是一个更简单的演示:jsfiddle.net/zazvkvmh