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

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

ただいまの
回答率

87.35%

javascript 同じ処理をまとめる

解決済

回答 4

投稿

  • 評価
  • クリップ 0
  • VIEW 1,123

score 10

https://teratail.com/questions/69420
上記URLを参照しましたが私の理解力が乏しいためわかりませんでした。

やりたいこととしましては、
カウントアップ、カウントダウンの部分をまとめて記述したいです。
function count_up_btn1(one,two,three){
}
変数を増やそうとしているためこの記述方法以外を教えていただけると幸いです。

よろしくお願いします。

<html>
<head>
    <title>TAG index Webサイト</title>
<script type="text/javascript">
var one = 0;
var two = 0;
var three = 0;
var total = 0;

function count_up_btn1(){
    //カウンタに 1 を加算
    document.getElementById( "one" ).innerHTML = ++one;
    document.getElementById( "total" ).innerHTML = ++total;
}
function count_down_btn1(){
    //カウンタから 1 を減算
    document.getElementById( "one" ).innerHTML = --one;
    document.getElementById( "total" ).innerHTML = --total;
}

function count_up_btn2(){
    //カウンタに 1 を加算
    document.getElementById( "two" ).innerHTML = ++two;
    document.getElementById( "total" ).innerHTML = ++total;
}

function count_down_btn2(){
    //カウンタから 1 を減算
    document.getElementById( "two" ).innerHTML = --two;
    document.getElementById( "total" ).innerHTML = --total;
}

function count_up_btn3(){
    //カウンタに 1 を加算
    document.getElementById( "three" ).innerHTML = ++three;
    document.getElementById( "total" ).innerHTML = ++total;
}

function count_down_btn3(){
    //カウンタから 1 を減算
    document.getElementById( "three" ).innerHTML = --three;
    document.getElementById( "total" ).innerHTML = --total;
}

</script> 

</head>
<body>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
    <tr>
        <th>種類</th>
        <th>プラス</th>
        <th>マイナス</th>
        <th>合計<br>回数</th>
        <th>残り<br>回数</th>
    </tr>
    <tr>
        <td align="center">1</td>
        <td align=center><input type="button" value="+" onClick="count_up_btn1()"></input></td>
        <td align=center><input type="button" value="-" onClick="count_down_btn1()"></input></td>
        <td align=center><span id="one">0</span></td>
        <td></td>
    </tr>
        <td align="center">2</td>
        <td align=center><input type="button" value="+" onClick="count_up_btn2()"></input></td>
        <td align=center><input type="button" value="-" onClick="count_down_btn2()"></input></td>
        <td align=center><span id="two">0</span></td>
        <td></td>
    </tr>
        <td align="center">3</td>
        <td align=center><input type="button" value="+" onClick="count_up_btn3()"></input></td>
        <td align=center><input type="button" value="-" onClick="count_down_btn3()"></input></td>
        <td align=center><span id="three">0</span></td>
        <td></td>
    </tr>
</table>
<br>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
<tr>
    <th>合計<br>回数</th>
</tr>
<tr>
    <td align=center><span id="total">0</span></td>
</tr>
</table>
</body>
</html>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 4

+2

処理をまとめるならこんな感じ
※微調整しました

<script>
window.addEventListener('DOMContentLoaded', ()=>{
  [].forEach.call(document.querySelectorAll('.count'),x=>{
    x.addEventListener('click',()=>{
      var view=x.closest('tr').querySelector('.view');
      var total=document.querySelector('#total');
      view.textContent=parseInt(view.textContent)+x.classList.contains('up')-x.classList.contains('down')
      total.textContent=[].map.call(document.querySelectorAll('.view'),x=>parseInt(x.textContent)).reduce((x,y)=>x+y);
    });
  });
});
</script> 

</head>
<body>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
    <tr>
        <th>種類</th>
        <th>プラス</th>
        <th>マイナス</th>
        <th>合計<br>回数</th>
        <th>残り<br>回数</th>
    </tr>
    <tr>
        <td align="center">1</td>
        <td align=center><input type="button" value="+" class="count up"></input></td>
        <td align=center><input type="button" value="-" class="count down"></input></td>
        <td align=center><span class="view">0</span></td>
        <td></td>
    </tr>
        <td align="center">2</td>
        <td align=center><input type="button" value="+" class="count up"></input></td>
        <td align=center><input type="button" value="-" class="count down"></input></td>
        <td align=center><span class="view">0</span></td>
        <td></td>
    </tr>
        <td align="center">3</td>
        <td align=center><input type="button" value="+" class="count up"></input></td>
        <td align=center><input type="button" value="-" class="count down"></input></td>
        <td align=center><span class="view">0</span></td>
        <td></td>
    </tr>
</table>
<br>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
<tr>
    <th>合計<br>回数</th>
</tr>
<tr>
    <td align=center><span id="total">0</span></td>
</tr>
</table>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

+2

こんにちは

リファクタリングの指針として、以下の2点が考えられます。

  • onetwothree, ... という id や変数を使わないようにすること
  • イベント属性を使わずに、控えめなJavaScript(※追記2) にすること

以下、上記を踏まえた修正案の一例です。

<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
    <tr>
        <th>種類</th>
        <th>プラス</th>
        <th>マイナス</th>
        <th>合計<br>回数</th>
        <th>残り<br>回数</th>
    </tr>
    <tr>
        <td align="center">1</td>
        <td align="center"><input type="button" value="+" /></td>
        <td align="center"><input type="button" value="-" /></td>
        <td align="center"><span>0</span></td>
        <td></td>
    </tr>
    <tr>
        <td align="center">2</td>
        <td align="center"><input type="button" value="+" /></td>
        <td align="center"><input type="button" value="-" /></td>
        <td align="center"><span>0</span></td>
        <td></td>
    </tr>
    <tr>
        <td align="center">3</td>
        <td align="center"><input type="button" value="+" /></td>
        <td align="center"><input type="button" value="-" /></td>
        <td align="center"><span>0</span></td>
        <td></td>
    </tr>
</table>
<br>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
<tr>
    <th>合計<br>回数</th>
</tr>
<tr>
    <td align=center><span id="total">0</span></td>
</tr>
</table>
document.addEventListener('DOMContentLoaded', function() {

    const totalSpan = document.getElementById('total');
    const rows = [...document.querySelectorAll('table:first-of-type tr')];

    rows.forEach((row, rowIndex) => {
        if (rowIndex === 0) return;

        const counterSpan = row.querySelector('span');
        const buttons = [...row.querySelectorAll('input')];

        buttons.forEach((btn, btnIndex) => {
            btn.addEventListener('click', () => {
                [counterSpan, totalSpan].forEach(span => {
                    span.textContent = +span.textContent + (btnIndex ? -1 : 1);
                });
            });
          });
      });

});

上記の回答に挙げたjavascriptのコードは、テーブルの行が増えても、増えた行に対応するためのコード追加、修正をする必要がないものになっています。たとえば、上記のHTMLのテーブルの行を単に4行追加して計7行にしたとしても、javascriptのコードには何も手を加える必要がないです。

ご質問に挙げられている元のjavascriptのコードを、テーブルが何行になっても追加、修正する必要がないものにするためには、

  • onetwothree, ... という id や変数を使わないようにすること

が、リファクタリングしていく際の指針のひとつになります。

追記1: onclick属性にスクリプトを書く例

hj_zebraさんのご質問にある元のコードで、HTMLの下記の部分

<input type="button" value="+" onClick="count_up_btn1()">


のように、input要素のonclick属性にスクリプトを直接書くという手法をそのまま使いつつ、かつ、コードをまとめる例を挙げておきます。

修正方法としては、上記を

<input type="button" value="+" onclick="count(this)">


のようにして、クリックされたボタンを引数にとる関数count(button) を作っておいて、どのボタンがクリックされてもこれに処理させるようにします。以下、その一例です。(初めに挙げた回答と同じく、onetwothree を使わないようにもしています。)

<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
    <tr>
        <th>種類</th>
        <th>プラス</th>
        <th>マイナス</th>
        <th>合計<br>回数</th>
        <th>残り<br>回数</th>
    </tr>
    <tr>
        <td align="center">1</td>
        <td align="center"><input type="button" value="+" onclick="count(this)" /></td>
        <td align="center"><input type="button" value="-" onclick="count(this)" /></td>
        <td align="center"><span>0</span></td>
        <td></td>
    </tr>
    <tr>
        <td align="center">2</td>
        <td align="center"><input type="button" value="+" onclick="count(this)" /></td>
        <td align="center"><input type="button" value="-" onclick="count(this)" /></td>
        <td align="center"><span>0</span></td>
        <td></td>
    </tr>
    <tr>
        <td align="center">3</td>
        <td align="center"><input type="button" value="+" onclick="count(this)" /></td>
        <td align="center"><input type="button" value="-" onclick="count(this)" /></td>
        <td align="center"><span>0</span></td>
        <td></td>
    </tr>
</table>
<br>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
<tr>
    <th>合計<br>回数</th>
</tr>
<tr>
    <td align=center><span id="total">0</span></td>
</tr>
</table>

以下は、 上記のボタンクリック時に使用する関数count(button)  の一例です。

function count(button) {
    const diff = +`${button.value}1`;
    const spans = [
      document.getElementById('total'),
      button.closest('tr').querySelector('span')
    ];
    spans.forEach(span => {
        span.textContent = +span.textContent + diff;
    });
}

追記2: 控えめなJavaScript

ご質問にある、下記のHTML

<input type="button" value="+" onClick="count_up_btn1()">


のように、HTML要素のonclickなどの属性に直接スクリプトを書くことで、イベントを処理させる書き方に対して、この回答の冒頭に書いたコードの下記の部分

btn.addEventListener('click', () => {
 ・・・
});


のように、プログラムの中でイベントハンドラを設定する書き方は、控えめなJavaScript(Unobtrusive JavaScript)と呼ばれることがあります。

HTML要素の属性である onclick や onchange はイベント属性と呼ばれますが、MDNのイベント属性の説明には、以下のように、使用を非推奨とする旨が書かれています。

警告: これらの属性を使うことは避けるべきです。これは HTML を巨大化し可読性を下げます。情報と振る舞いの関心事が正しく分離されておらず、発見が困難なバグを生み出します。その上に、Event 属性の使い方はほとんどの場合、Window オブジェクト上のグローバル関数にスクリプトを晒す原因になります。これはグローバルの名前空間を汚染します。

これらの属性が魅力的で簡単に使うことができたとしても、これを使うのは避けるべきです。代わりに、イベントリスナーを追加する為には EventTarget.addEventListener() 関数を使ってください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

checkベストアンサー

+1

修正案の一例です。なるべく元の感じを殺さないように修正してみました。

<html>
<head>
    <title>TAG index Webサイト</title>
<script type="text/javascript">
var counter = {
  one: 0,
  two: 0,
  three: 0,
  total: 0
};

function count_up(id){
    //カウンタに 1 を加算
    document.getElementById(id).innerHTML = ++counter[id];
    document.getElementById("total").innerHTML = ++counter['total'];
}

function count_down(id){
    //カウンタから 1 を減算
    document.getElementById(id).innerHTML = --counter[id];
    document.getElementById("total").innerHTML = --counter['total'];
}

</script> 

</head>
<body>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
    <tr>
        <th>種類</th>
        <th>プラス</th>
        <th>マイナス</th>
        <th>合計<br>回数</th>
        <th>残り<br>回数</th>
    </tr>
    <tr>
        <td align="center">1</td>
        <td align=center><input type="button" value="+" onClick="count_up('one')"></input></td>
        <td align=center><input type="button" value="-" onClick="count_down('one')"></input></td>
        <td align=center><span id="one">0</span></td>
        <td></td>
    </tr>
        <td align="center">2</td>
        <td align=center><input type="button" value="+" onClick="count_up('two')"></input></td>
        <td align=center><input type="button" value="-" onClick="count_down('two')"></input></td>
        <td align=center><span id="two">0</span></td>
        <td></td>
    </tr>
        <td align="center">3</td>
        <td align=center><input type="button" value="+" onClick="count_up('three')"></input></td>
        <td align=center><input type="button" value="-" onClick="count_down('three')"></input></td>
        <td align=center><span id="three">0</span></td>
        <td></td>
    </tr>
</table>
<br>
<table border="1"cellspacing="0" cellpadding="5"  bordercolor="black">
<tr>
    <th>合計<br>回数</th>
</tr>
<tr>
    <td align=center><span id="total">0</span></td>
</tr>
</table>
</body>
</html>

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

どこまで理解できているのでしょうか。
失礼ですが、質問にあるサンプル、自分なりにやったものでしょうか。
たまに切り貼りしただけの、全く理解すらしていない(そもそもJavaScriptって何?おいしいの?っていうレベルだったり)場合があります。

知識レベルに応じた説明があるので、できるだけ「どこまで理解できたのか」「どこが不明瞭なのか」を記述しすると説明しやすいです。


[追記1]

サンプルソースは自分で作成したものになります。

Okです。関数の組み方は...ご存じですよね?
わからないのなら、入門書(または入門サイト)をお読みください。
まずは基礎ができていないと無理ですから。

ボタンの数が多く、できるだけ汎用性を持たせた関数を作成したいということですよね。

まず、基本的な部分を考えてみましょう。

function count_up_btn1(){
    //カウンタに 1 を加算
    document.getElementById( "one" ).innerHTML = ++one;
    document.getElementById( "total" ).innerHTML = ++total;
}
function count_down_btn1(){
    //カウンタから 1 を減算
    document.getElementById( "one" ).innerHTML = --one;
    document.getElementById( "total" ).innerHTML = --total;
}

function count_up_btn2(){
    //カウンタに 1 を加算
    document.getElementById( "two" ).innerHTML = ++two;
    document.getElementById( "total" ).innerHTML = ++total;
}

function count_down_btn2(){
    //カウンタから 1 を減算
    document.getElementById( "two" ).innerHTML = --two;
    document.getElementById( "total" ).innerHTML = --total;
}

function count_up_btn3(){
    //カウンタに 1 を加算
    document.getElementById( "three" ).innerHTML = ++three;
    document.getElementById( "total" ).innerHTML = ++total;
}

function count_down_btn3(){
    //カウンタから 1 を減算
    document.getElementById( "three" ).innerHTML = --three;
    document.getElementById( "total" ).innerHTML = --total;
}


がやりたいこと(最終的に行いたいこと)ですよね。

共通部分を見ると、

常に id が"one", "two", "tree" のどれかをインクリメント( ++oneとか )やデクリメント ( --one とか ) して、id がtotal のエリアを インクリメントまたはデクリメントしていますね。

つまり、共通項だけをまとめて書くと

// ただし<..> とあるのは何かしらの変数または定数だとして
document.getElementById( <ID> ).innerHTML = <増減>;
document.getElementById( "total" ).innerHTML = <増減>;


ですよね。

それなら、単純にこの式をコード化すればいいかと思います。

ただし、<ID> と<増減>だけが不定。
それなら、これを管理する関数 を作って、これに管理させる。

ただ、私の書き方ですと、プロトタイプっていう、ほかの言語だとクラス...を変化させたようなものを使う必要があるので、関数で結構です。
ヒント: プロトタイプ JavaScript

// プロトタイプ NumberManagerを定義

function calcNumberWithId(id){
             // 仮に "one"のときは減算で "two"なら加算すると仮定
             if( id == "one" ){
                        // ここで one をインクリメントする
                        // あと total も
                        return one;
             }else if( id == "two" ){
                        // ここでtwo をデクリメントする
                        // あと total も
                        return two;
             }
         // 処理されなかった...
         return undefined;
}

みたいにしておけば、

グローバルエリアとかでNumberManagerのインスタンスを生成しておいて、

// ただし<..> とあるのは何かしらの変数または定数だとして
// また numberManager は NumberManagerのオブジェクトだとして
function pushButton( id ){
   // 関数calcNumberWithIdを介して操作し、戻り値のnumを設定する
   var num = calcNumberWithId(id);
   document.getElementById( id ).innerHTML = num;
   document.getElementById( "total" ).innerHTML = total;
}

みたいに簡略化できる。

もっといい方法があるのかもしれませんが、私ならこういう風にするかなぁ。

追記:
あ、忘れていた...
呼び出し側である、<input type="button" value="-" onClick="count_down_btn3()"></input> では、

count_down_btn3関数じゃなくて、pushButton関数を呼び出してください。

例:

<input type="button" value="-" onClick="pushButton('three')"></input>

すると、

関数Aが関数Bを呼び出している...みたいな体で書くと、

pushButton( "three" );
みたいになる。

後から考えると、countDown_pushButton( "three" ); countUp_pushButton( "three" ); とかに分離してもいいかなぁ。
(大雑把な考え方は一緒)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/10/29 13:43

    >BeatStarさん
    サンプルソースは自分で作成したものになります。
    javasscriptはほんの少ししか理解できていないため説明などしていただけると助かります。

    キャンセル

  • 2019/10/29 13:45

    追記しますね。

    キャンセル

  • 2019/10/29 13:58

    お願いします

    キャンセル

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

  • ただいまの回答率 87.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る