1. Illustration
In a javascript function, if a variable is not declared before assigning value, it is considered as a state variable of the function, even when the function returns, the state variable still exists, shared across calls of the function,
if a variable is declared (e.g. var x), then when the function in which the variable is declared returns, the life of the variable also end, namely the variable does not exist anymore, the object referenced by the variable is ready for garbage collection.
2. one example of while loop never exit due to state variable
In the following example, if without var i;
, i
is state variable of the function. When calling this function, assuming that this_object_comments.length
is 4, and the forth comment (i = 3) also has comments, it will also call the function to show its comments (recursive call), namely:
if (comment['id'] in js_comments) {
show_comments(comment['id'], parent_node=comment_container);
assuming the forth comment has 1 comment, namely, this_object_comments.length
is 1 for the forth comment, and its comment has no comment, so after showing the comment of the forth comment, the call for the forth comment returns, at this time, i = 2 (for (i = 0; i < this_object_comments.length; i++)
). and now the execution back to the first call, before the inner call, i = 3, and we expect after the inner call, still i = 3, but due to i is not declared before assignment, it is state variable of the function, shared across calls, i is changed in the inner call to 2, so now i = 2, then again, after i++, i = 3, again call the function for the forth comment, again at the end of the call for the forth comment, i = 2, then again back to the first call with i = 2, then repeat this circle forever, while loop will never exit.
[SOLUTION]
declare i as `var i' before assignment.
<script>
var js_comments = {{ comments | tojson }};
var js_post = {{ post | tojson }};
console.log("js_comments: ");
console.log(js_comments);
function show_comments(comment_object_id,
parent_node=document.body) {
var comments_container = document.createElement('ul');
comments_container.class = "comments";
parent_node.appendChild(comments_container);
var this_object_comments = js_comments[comment_object_id];
console.log("this_object_comments: ");
console.log(this_object_comments);
var i;
for (i = 0; i < this_object_comments.length; i++) {
comment = this_object_comments[i];
console.log("i: ");
console.log(i);
console.log("comment['id'] at for begin: ");
console.log(comment['id']);
var comment_container = document.createElement('li');
var comment_date = document.createElement('div');
comment_date.class = "comment-date";
comment_date.innerHTML = comment['created'];
comment_container.appendChild(comment_date);
var comment_author = document.createElement('div');
comment_author.class = "comment-author";
comment_author.innerHTML = comment['username'];
comment_container.appendChild(comment_author);
var comment_body = document.createElement('div');
comment_body.class = "comment-body";
comment_body.innerHTML = comment['body'];
comment_container.appendChild(comment_body);
var reply = document.createElement('a');
reply.href = "/" + js_post['id'] + "/" + comment['id'] + "/reply";
reply.innerHTML = "reply";
comment_body.appendChild(reply);
comments_container.appendChild(comment_container);
if (comment['id'] in js_comments) {
console.log("comment['id'] in js_comments");
console.log(comment['id']);
console.log(js_comments[comment['id']]);
show_comments(comment['id'], parent_node=comment_container);
}
}
}
show_comments(0,);
</script>