这个 javascript 闭包有什么问题?
What is wrong with this javascript closure?
我有一个递归函数 (exploreNode),它更新在其正上方声明的变量 (branch_queue) 的值。
当我 运行 正常时(没有闭包函数),它按预期工作。
当我放置在闭包函数内部时,递归函数没有按照预期的方式遍历子节点。它保持在同一个初始节点上,直到 "Max Call Stack" 错误触发。
递归函数的目的是探索 JSON 树,直到找到所需的 ID。当它遍历树时,branch_queue var 会使用到感兴趣节点的路线图进行更新。
关闭是为了不将 branch_queue 作为全局函数。
我在 es6 和 es5 中都试过了,认为这可能是作用域和使用 "const" 和 "let" 的问题。
示例如下。
我还有下面的代码块,它可以在没有关闭的情况下工作。
我作为参数输入的树
let u = [
{
id: 0,
label: 'l0',
children: [
{
id: 1,
label: 'l1'
},
{
id: 2,
label: 'l2',
children: [
{
id: 3,
label: 'l3'
},
{
id: 4,
label: 'l4'
},
{
id: 5,
label: 'l5'
},
{
id: 6,
label: 'l6',
children: [
{
id: 7,
label: 'l7'
},
{
id: 8,
label: 'l8'
},
{
id: 9,
label: 'l9'
},
{
id: 10,
label: 'l10'
}
]
}
]
}
]
}
]
什么起作用了
let branch_queue = [];
// Assumes that the ID exists!
const exploreNode = (nodeIdOfInterest, nodeTree) => {
// var branch_queue = [];
for (let i = 0; i < nodeTree.length; i++) {
const nodeToCheck = nodeTree[i];
if (nodeToCheck.id == nodeIdOfInterest) {
branch_queue.push(nodeToCheck.id);
return nodeToCheck.label;
} else if(nodeToCheck.children) {
branch_queue.push(nodeToCheck.id);
return exploreNode(nodeIdOfInterest, nodeToCheck.children);
}
}
}
exploreNode(3, contentTree);
console.log(branch_queue); // prints the correct roadmap
什么不起作用
ES5
function fn (nodeIdOfInterest, nodeTree) {
let branch_queue = [];
console.log('here');
// Assumes that the ID exists!
function exploreNode () {
var branch_queue = [];
console.log('in here');
for (var i = 0; i < nodeTree.length; i++) {
var nodeToCheck = nodeTree[i];
console.log(`${nodeToCheck.label} : ${nodeToCheck.id}`);
if (nodeToCheck.id == nodeIdOfInterest) {
console.log('found it');
branch_queue.push(nodeToCheck.id);
return nodeToCheck.label;
} else if(nodeToCheck.children) {
console.log('checking children');
branch_queue.push(nodeToCheck.id);
return exploreNode(nodeIdOfInterest, nodeToCheck.children);
}
}
};
exploreNode();
return branch_queue;
}
console.log(fn(3, contentTree)); // throws call stack error
ES6
const fn = (nodeIdOfInterest, nodeTree) => {
let branch_queue = [];
console.log('here');
// Assumes that the ID exists!
const exploreNode = () => {
// var branch_queue = [];
console.log('in here');
for (let i = 0; i < nodeTree.length; i++) {
let nodeToCheck = nodeTree[i];
console.log(`${nodeToCheck.label} : ${nodeToCheck.id}`);
if (nodeToCheck.id == nodeIdOfInterest) {
branch_queue.push(nodeToCheck.id);
return nodeToCheck.label;
} else if(nodeToCheck.children) {
branch_queue.push(nodeToCheck.id);
return exploreNode(nodeIdOfInterest, nodeToCheck.children);
}
}
};
exploreNode();
return branch_queue;
};
console.log(fn(3, contentTree)); // throws call stack error
预期输出=> [0 2 3]
实际=>。最大调用堆栈错误
递归函数永远不会超出第一层,并无限期地重复。
nodeTree
在 exploreNode
的递归版本中始终是相同的起点,即传入 fn
的起点。该版本中对 exploreNode
的每次调用都是全新的:您对 exploreNode
的调用正在传递参数,但它忽略了它们。 "what did work" 版本不会忽略传递给它的参数,所以它可以工作。
我有一个递归函数 (exploreNode),它更新在其正上方声明的变量 (branch_queue) 的值。 当我 运行 正常时(没有闭包函数),它按预期工作。
当我放置在闭包函数内部时,递归函数没有按照预期的方式遍历子节点。它保持在同一个初始节点上,直到 "Max Call Stack" 错误触发。
递归函数的目的是探索 JSON 树,直到找到所需的 ID。当它遍历树时,branch_queue var 会使用到感兴趣节点的路线图进行更新。
关闭是为了不将 branch_queue 作为全局函数。
我在 es6 和 es5 中都试过了,认为这可能是作用域和使用 "const" 和 "let" 的问题。 示例如下。
我还有下面的代码块,它可以在没有关闭的情况下工作。
我作为参数输入的树
let u = [
{
id: 0,
label: 'l0',
children: [
{
id: 1,
label: 'l1'
},
{
id: 2,
label: 'l2',
children: [
{
id: 3,
label: 'l3'
},
{
id: 4,
label: 'l4'
},
{
id: 5,
label: 'l5'
},
{
id: 6,
label: 'l6',
children: [
{
id: 7,
label: 'l7'
},
{
id: 8,
label: 'l8'
},
{
id: 9,
label: 'l9'
},
{
id: 10,
label: 'l10'
}
]
}
]
}
]
}
]
什么起作用了
let branch_queue = [];
// Assumes that the ID exists!
const exploreNode = (nodeIdOfInterest, nodeTree) => {
// var branch_queue = [];
for (let i = 0; i < nodeTree.length; i++) {
const nodeToCheck = nodeTree[i];
if (nodeToCheck.id == nodeIdOfInterest) {
branch_queue.push(nodeToCheck.id);
return nodeToCheck.label;
} else if(nodeToCheck.children) {
branch_queue.push(nodeToCheck.id);
return exploreNode(nodeIdOfInterest, nodeToCheck.children);
}
}
}
exploreNode(3, contentTree);
console.log(branch_queue); // prints the correct roadmap
什么不起作用 ES5
function fn (nodeIdOfInterest, nodeTree) {
let branch_queue = [];
console.log('here');
// Assumes that the ID exists!
function exploreNode () {
var branch_queue = [];
console.log('in here');
for (var i = 0; i < nodeTree.length; i++) {
var nodeToCheck = nodeTree[i];
console.log(`${nodeToCheck.label} : ${nodeToCheck.id}`);
if (nodeToCheck.id == nodeIdOfInterest) {
console.log('found it');
branch_queue.push(nodeToCheck.id);
return nodeToCheck.label;
} else if(nodeToCheck.children) {
console.log('checking children');
branch_queue.push(nodeToCheck.id);
return exploreNode(nodeIdOfInterest, nodeToCheck.children);
}
}
};
exploreNode();
return branch_queue;
}
console.log(fn(3, contentTree)); // throws call stack error
ES6
const fn = (nodeIdOfInterest, nodeTree) => {
let branch_queue = [];
console.log('here');
// Assumes that the ID exists!
const exploreNode = () => {
// var branch_queue = [];
console.log('in here');
for (let i = 0; i < nodeTree.length; i++) {
let nodeToCheck = nodeTree[i];
console.log(`${nodeToCheck.label} : ${nodeToCheck.id}`);
if (nodeToCheck.id == nodeIdOfInterest) {
branch_queue.push(nodeToCheck.id);
return nodeToCheck.label;
} else if(nodeToCheck.children) {
branch_queue.push(nodeToCheck.id);
return exploreNode(nodeIdOfInterest, nodeToCheck.children);
}
}
};
exploreNode();
return branch_queue;
};
console.log(fn(3, contentTree)); // throws call stack error
预期输出=> [0 2 3] 实际=>。最大调用堆栈错误
递归函数永远不会超出第一层,并无限期地重复。
nodeTree
在 exploreNode
的递归版本中始终是相同的起点,即传入 fn
的起点。该版本中对 exploreNode
的每次调用都是全新的:您对 exploreNode
的调用正在传递参数,但它忽略了它们。 "what did work" 版本不会忽略传递给它的参数,所以它可以工作。