![](http://oshiete.xgoo.jp/images/v2/pc/qa/question_title.png?e8efa67)
プログラミング初心者です。
かなり初歩的な理解の間違いをしているかもですが、その都度指摘していただけたら幸いです。
ふとHTMLのdocumentを構成している全ノードの情報(具体的にはinnerHTMLとノード名について)を表示させようと思い、次のようなコードを書きました。
function getElementsinfo(anode){
if ((anode.childNodes.length) == 0){
alert(anode.innerHTML);
alert(anode.nodeName);
alert("最下層ノードです");
}else{
nagasa = anode.childNodes.length;
for(j=0;j<nagasa;j++){
alert(anode.childNodes[j].innerHTML);
alert(anode.childNodes[j].nodeName);
getElementsinfo(anode.childNodes[j]);
}
}
return 0;
}
getElementsByinfo(document.body);
私の意図するところとしては、最下位のノード(子ノードが存在しないノード)までたどり着いた場合に、forループを利用してnextSiblingにあたるノードの情報を表示できるようにしたかったのですが、
どうも最下位のノードまでたどり着いたところで関数の実行が終了してしまうようなのです。
つまり、ノードが
1
|_____
| | |
11 12 13
|_______
| | |
111 112 113
のような構造をしている場合
1→11→111→112→113→12→121→122…のようにノードの情報を表示させたかったのですが
1→11→111まで表示してプログラムの実行が止まってしまっています。
この問題に対し貴重なご意見をいただきたく存じます。
現状の私の理解では解決策を思いつかず、投稿させていただきました。
質問のわかりにくい点については随時補足させていただきます。
No.2ベストアンサー
- 回答日時:
グローバル変数と局所変数の違いはわかりますか?
以下のように、 var を使って変数を宣言した場合、関数内をスコープとする変数になります。
var variable = 100;
一方、関数内で var を使って宣言されていない変数を使用すると、自動的にグローバル変数となり、あらゆる場所から参照可能になります。
zabiora さんの例の場合、変数 nagasa と変数 j はグローバル変数となってしまっています。 そのため再帰的に呼び出した関数内での変数 nagasa と、元の関数内の変数 nagasa は同じ変数ということになり、再帰的に呼び出された関数内で変数 nagasa に値を代入してしまうと問題発生・・・、というわけです。
解決するには、変数 nagasa と変数 j を var をつけて宣言すればいいと思います。 変数名を一部変えちゃってますが、こんな感じに。
function getElementsinfo( aNode ){
if( aNode.childNodes.length == 0 ) {
window.alert( aNode.nodeValue
+ "\n" + aNode.nodeName
+ "\n最下層ノードです");
} else {
// 変数 length と変数 i を局所変数に
var length = aNode.childNodes.length;
for( var i = 0; i < length; i++ ) {
window.alert(aNode.childNodes[i].nodeValue
+ "\n" + aNode.childNodes[i].nodeName);
getElementsinfo( aNode.childNodes[i] );
}
}
return 0;
}
getElementsinfo(document.body);
あと innerHTML プロパティは W3C DOM の勧告にはない独自仕様なので使わないほうが吉かと。 どうせループして全ノードをチェックするのですから nodeValue プロパティでいいのではないかと思います。 (そんなわけで上のサンプルでも nodeValue プロパティを使用しています。)
非常にわかりやすい解説に感謝致します。
グローバル変数と局所変数ですか…。完全に失念しておりました。
初め一通り学んだときに知識として入れていても、
いざコードを書くときにちゃんと思い出せなければいけませんね。
innerHTMLは正式な仕様ではないのですか。
これからはちゃんとW3Cの文書を読む癖もつけていきたいです。
本当に回答ありがとうございました。
No.3
- 回答日時:
よけいなことかもしれないけど
if ((anode.childNodes.length) == 0){
は、
if (! hasChildNodes()) {
でよくない?
あら~ともうざいので、
alert([anode.innerHTML,'\n',anode.nodeName]);
とか、
けんさくするのなら
function getNextElement (n) {
var e;
while (n) {
e = n.firstChild || n.nextSibling
if (! e) {
do {
if (! (n = n.parentNode)) return null;
} while (! (e = n.nextSibling))
}
n = e;
if (1 === n.nodeType) return n;
}
return null;
}
とか。
まったくよけいなことだけど ^^;
回答ありがとうございます。
>よけいなことかもしれないけど
いえいえ、全く余計では無いです。むしろ色々なやり方、より簡潔なやり方を教えていただいて感謝します。
私は本当に知識が乏しいので、このような指摘もありがたいです。
No.1
- 回答日時:
/* 変数は必ず宣言しよう */
/*
仕様未確認。
Minefield(Firefox 3.6a1pre)で動かす限り,
変数宣言がなかった結果,ここに宣言されたものとされるっぽい。
なので再帰を実行して戻ってきたとき,呼び出し前の変数の値は呼び出し先によって上書きされているものと思われる。
*/
var nagasa;
var j;
function getElementsinfo(anode){
if ((anode.childNodes.length) == 0){
alert(anode.innerHTML);
alert(anode.nodeName);
alert("最下層ノードです");
}else{
nagasa = anode.childNodes.length;
for(j=0;j<nagasa;j++){
alert(anode.childNodes[j].innerHTML);
alert(anode.childNodes[j].nodeName);
getElementsinfo(anode.childNodes[j]);
}
}
return 0;
}
getElementsinfo(document.body); /* 関数名にByが入ってたので撤去 */
=================================
function getElementsinfo(anode){
if ((anode.childNodes.length) == 0){
alert(anode.innerHTML);
alert(anode.nodeName);
alert("最下層ノードです");
}else{
var nagasa = anode.childNodes.length; /* varをつけて宣言してみる */
for(var j=0;j<nagasa;j++){ /* varをつけて宣言してみる */
alert(anode.childNodes[j].innerHTML);
alert(anode.childNodes[j].nodeName);
getElementsinfo(anode.childNodes[j]);
}
}
return 0;
}
getElementsinfo(document.body);
/*
実際にはalertがいちいち表示されるのはうざかったので
改行を挟みながら文字列をつなげるようにして
結果の表示は最後だけにした。alertじゃなくても別に出力用の要素があってもいいよね
*/
回答有難うございます。
変数の宣言というのはやはり明示的にするべきなのですね。
自分の理解の至らなさを痛感させられます…。
修正後のコードまでご丁寧に示していただき本当に感謝いたします。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
idを使わずにonclickで自身の要...
-
関数でy=g(x)のgとは何の略です...
-
要素名がスペースを含む場合のj...
-
getElementByIdを使用したグロ...
-
jqueryuiのdialog
-
XMLHttpRequestオブジェクトが...
-
処理前の「お待ちください」
-
<HEAD>内と<HEAD>後のfunction...
-
jqueryのグローバル変数とロー...
-
(function(){})()の意味
-
functionから別のfunctionを実...
-
食材の期限を管理するためにGAS...
-
ActiveXobjectが作成できない
-
javascriptで入力フォームに日...
-
同じIDで定義した要素の配列を...
-
ASP.NETのコントロールの値をJa...
-
JavaScriptとHTMLの課題です
-
jspからjavascriptの変数引継ぎ
-
この配列は何?
-
javascriptで行を抽出したいです。
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
関数でy=g(x)のgとは何の略です...
-
idを使わずにonclickで自身の要...
-
functionから別のfunctionを実...
-
jQueryの :not() .not() が有効...
-
jslintのエラーについて質問
-
クリックすると上に開くアコー...
-
関数名をテキストから読み込む...
-
getElementByIdを使用したグロ...
-
XMLHttpRequestでキャッシュを...
-
jQueryの"return false"の役割...
-
JAVAスクリプトで指定時間以降...
-
JavaScriptの日付の比較
-
jQueryでzipを解凍読み込みする...
-
コードをスマートにさせたい。
-
XMLHttpRequestオブジェクトが...
-
ページ内に複数表がある場合のT...
-
要素名がスペースを含む場合のj...
-
(function(){})()の意味
-
javascriptのreplaceについて
-
jqueryuiのdialog
おすすめ情報