質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

Q&A

解決済

5回答

2271閲覧

javascript メソッドがうまく組めない

earnest_gay

総合スコア615

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

0グッド

0クリップ

投稿2017/01/12 17:25

編集2017/01/12 17:51

あまり実行ファイルにベタベタ書くのが好きではないので、できるだけ関数内に入れて外部ファイルにしておきたくて記述してみたんですが、動かないです。

JSは不慣れというところもありますが、どうすれば動くでしょうか?

<script type="text/javascript"> countDown("counter"); function countDown(id) { var count = 5; //カウントの初期値 setInterval(countDownStart(id),1000); //1秒毎にcountDown()を呼び出し function countDownStart(id) { if(count > 0){ count--; //減算 document.getElementById(id).innerHTML=count; } else if(count == 0) { //countの秒数経過後に遷移。ブラウザバックはさせない。 location.replace('<?= (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] ."/".$cfg_set['FILE_NAME_LOGIN'] ?> '); } } } </script> <p><span id="counter">5</span>秒後にログインページへ移動します。</p>

下記は動きます。

<script type="text/javascript"> let count = 5; //カウントの初期値 setInterval('countDown("counter")',1000); //1秒毎にcountDown()を呼び出し function countDown(id) { if(count > 0){ count--; //減算 document.getElementById(id).innerHTML=count; } else if(count == 0) { //countの秒数経過後に遷移。ブラウザバックはさせない。 //location.replace('<?= (empty($_SERVER["HTTPS"]) ? "http://" : "https://") . $_SERVER["HTTP_HOST"] ."/".$cfg_set['FILE_NAME_LOGIN'] ?> '); } } </script> <p><span id="counter">5</span>秒後にログインページへ移動します。</p>

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kei344

2017/01/12 17:43

タイトルの「 jsvascript 」は「JavaScript」では?
kei344

2017/01/12 17:54

回答が付いた質問の編集は慎重に行ってください。質問文のコードについて回答にて指摘があった場合は「追記」し、元のコードを編集する場合も「直したこと」がわかるようにしてください。
guest

回答5

0

動作しない理由は、setIntervalの第一引数で、関数そのものを渡しているのでは無く関数を実行した結果を渡しているからです。countDownStart()関数の定義から仮引数を無くし(つまり、funciton countDownStart() {...}と書くと言うこと)、setInterval(countDownStart,1000);と書けば、動作すると思います。


【解説】

countDownStart関数そのものですが、countDownStart(id)関数をidを引数として実行した戻り値になります。return文で戻り値が指定されていない場合は、JavaScriptはundefined値を返しますので、この場合はundefined値です。

もうちょっと詳しく言います。setInterval(countDownStart(id),1000);を評価するとき、まず、それぞれの引数を評価します。引数は、countDownStart(id)1000です。countDownStart(id)の評価では、idを引数にcountDownStart()を**実行(呼び出)**して、その戻り値であるundefined値に置き換わります。1000は数値リテラルですのでその評価結果も1000を表す数値です。よって、引数の評価により、setInterval(【undefined値】,【1000という数値】);となってから、setInterval()が評価されます。第一引数の値はundefined値ですので、1000ミリ秒経っても何もされません。

では、setInterval(countDownStart,1000);と書いた場合はどうなるかというと、countDownStartは関数そのものを指し示す変数ですので、その評価の結果も関数そのものです。つまり、引数の評価後もsetInterval(【countDownStartという関数】,【1000という数値】);となります。ですので、1000ミリ秒経つと、第一引数の関数そのものが実行(呼び出)されます。

なお、引数をなくす意味ですが、idという引数は変数countと同じくクロージャーによって内部関数であるcountDownStart()使用できます。わざわざ引数として渡す必要はありません。もし、どうしても引数を付けたい場合はcountDownStart.bind(this, id)(thisの部分は今回使用していないので何でもいいです)とbind()を用いて引数が束縛された新たな関数を作ったり、無名関数で囲って新たな関数にする等の対応が必要になります。

【補足】

その他の注意事項を書いておきます。

  1. 実行されるscriptタグは最後(bodyの終了タグ直前)に書くことを推奨します。最後に書くと、jQueryでの$(funciton{...});と実質同じ効果が得られます。今回はsetInterval()によって1000ミリ秒後にしかspanの部分を見に行かないためうまくいきますが、今回のような書き方だと、script内が最初に実行されるときに、spanの部分をまだブラウザが認識していないということに注意してください。
  2. function宣言の巻き上げにより関数定義が後ろの方にあっても動作しますが、巻き上げの影響を十分理解していなければ、そのような書き方は推奨できません。関数は呼び出される場所よりも前に書くことを推奨します。

投稿2017/01/12 21:37

編集2017/01/13 09:36
raccy

総合スコア21735

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

こうしてください

javascript

1<script> 2var count = 5; 3var timerId; 4countDown("counter"); 5function countDown(id) { 6 timerId=setInterval(function(){countDownStart(id)},1000); 7} 8function countDownStart(id) { 9 if(count > 0){ 10 count--; 11 document.getElementById(id).innerHTML=count; 12 } else if(count == 0) { 13 clearInterval(timerId); 14 alert("!"); 15 } 16} 17 18</script> 19 20<p><span id="counter">5</span>秒後にログインページへ移動します。</p>

投稿2017/01/13 00:46

編集2017/01/13 00:48
yambejp

総合スコア114769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

ベストアンサー

javascript

1 function countDown(id) { 2 var sec = 5, //カウントの初期値 3 counter = document.getElementById(id); // 要素の取得 4 5 // 実行 6 count(sec); 7 8 function count(sec) { 9 counter.textContent = sec; 10 11 if (sec === 0) { 12 //countの秒数経過後に遷移。ブラウザバックはさせない。 13 // ここにlocation.replace等の処理を入れる 14 return; 15 } 16 17 // 秒数を1減らす 18 sec--; 19 20 // 1秒置いて再実行 21 setTimeout(function() { 22 count(sec); 23 }, 1000); 24 }; 25 }; 26 27// HTMLのロード終了後にカウントダウン関数実行 28 document.addEventListener("DOMContentLoaded", function() { 29 countDown("counter"); 30 });

投稿2017/01/13 01:54

編集2017/01/13 01:55
yamato_hikawa

総合スコア2092

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

setInterval

setInterval は第3引数以降(可変引数)を指定する事でコールバック関数に引数を渡すことが出来ます(HTML5 規定)。

JavaScript

1setInterval(countDownStart, 1000, id);

Polyfill

setInterval の第3引数以降は IE10- が未対応です。
Windows Vista SP2 付属の IE9 は2017/04/11までサポートが継続されている為、そちらを対象ブラウザにするならMDNにあるPolyfillを使う事で対応できます。

サンプルコード

HTML

1<p><span id="counter">5</span>秒後にログインページへ移動します。</p> 2<ul> 3 <li><a href="https://teratail.com/questions/61815">JavaScript - javascript メソッドがうまく組めない(61815)|teratail</a></li> 4</ul> 5<script> 6'use strict'; 7function handleCountDown (id) { 8 var textNode = this.document.getElementById(id).firstChild, 9 count = --textNode.data; 10 11 if (count < 1) { 12 location.replace('http://example.com/'); 13 } 14} 15 16setInterval(handleCountDown, 1000, 'counter'); 17</script>

関数式にすればグローバル汚染もなくなります。
その場合は引数 id を排除してもいいですが、設計指針の好みの範疇だと思います。

JavaScript

1'use strict'; 2setInterval(function handleCountDown (id) { 3 var textNode = this.document.getElementById(id).firstChild, 4 count = --textNode.data; 5 6 if (count < 1) { 7 location.replace('http://example.com/'); 8 } 9}, 1000, 'counter');

(2017/01/13 11:45 追記)
上記コードでは分かりやすいようにローカル変数を使用していますが、それぞれの変数は1回ずつの使用なので変数宣言を省略する事も出来ます。

JavaScript

1setInterval(function handleCountDown (id) { 2 if (--this.document.getElementById(id).firstChild.data < 1) { 3 location.replace('http://example.com/'); 4 } 5}, 1000, 'counter');

更新履歴

  • 2017/01/13 11:35 サンプルコードを追記
  • 2017/01/13 11:45 ローカル変数省略版のサンプルコードを追記

Re: rento さん

投稿2017/01/13 01:36

編集2017/01/13 02:46
think49

総合スコア18162

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

関数 countDown を実行していないからでは?


また、setInterval に文字列を渡していますが、関数を渡すほうが良いと思います。

【setTimeoutとかsetIntervalって内部的にevalしてんのかよ - tumblr】
http://shim0mura.hatenadiary.jp/entry/20110619/1308490737

【setTimeout、setIntervalに指定する関数は出来る限り文字列で渡してはいけない。 - ひよっこPGのブログ】
http://buzzword111.hatenablog.com/entry/2014/01/15/125131


追記:

ページがロードされたタイミングで動かしたいなら。

【DOMContentLoaded - Web 技術のリファレンス | MDN】
https://developer.mozilla.org/ja/docs/Web/Reference/Events/DOMContentLoaded

JavaScript

1 document.addEventListener("DOMContentLoaded", function(event) { 2 console.log("DOM fully loaded and parsed"); 3 });

それより前でよいなら。

【即時関数のメリットと主な用途|もっこりJavaScript|ANALOGIC(アナロジック)】
http://analogic.jp/immediate-function/

JavaScript

1(function () { 2 //関数の中身・・・ 3}());

【JavaScriptで即時関数を使う理由 - Qiita】
http://qiita.com/katsukii/items/cfe9fd968ba0db603b1e

【JavaScriptの即時関数とは何か。意味やメリット、引数の使い方についてまとめてみた。 - ゴトーのブログ】
http://www.gamehuntblog.com/entry/javascript-about-immediate-function

投稿2017/01/12 17:35

編集2017/01/12 17:41
kei344

総合スコア69398

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

earnest_gay

2017/01/12 17:52

冒頭のコードを一から修正追加しました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問