3週間前に投稿

配列として定義した時に悩んだ事

2021年11月16日

この記事は約 19 分で読めます。

4.5

まず、経緯として以下の
「カウントダウンタイマー」を
実装したいと思い以下のような
コードにしてみました。

そして、配列にして書いたら
どうなるのか試してみたところ、
かなり悩んだという話です。

カウントダウンタイマーを実装してみた

function countdown() {
  const now = new Date();
  const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
  const differ = future.getTime() - now.getTime();
  const sec = (Math.floor(differ / 1000) % 60);
  const min = (Math.floor(differ / 1000 / 60) % 60);
  const hour = (Math.floor(differ / 1000 / 60 / 60));

document.getElementById("hour").innerHTML = hour.toString().padStart(2,"0");
document.getElementById("min").innerHTML = min.toString().padStart(2,"0");
document.getElementById("sec").innerHTML = sec.toString().padStart(2,"0");

setTimeout(countdown,1000);//1秒毎に繰り返す
}
countdown();
<div class="box">今日が終わるまで
  <div class="timer">あと <span id="hour"></span>時間 <span id="min"></span>分 <span id="sec"></span>秒 </div>
</div>
ワン U・(エ)・U ワン
今日が終わるまで
あと 時間
だ ワンワン
(参考)
1.CSS アニマルBOX (囲み枠・飾り枠) : https://love-wave.com/css-waku-animal/
2.【JavaScript】爆速でカウントダウンタイマーを実装する方法 : https://pote-chil.com/js_timer/

明日、明後日、任意の日付を取得

const now = new Date();  //現在時刻を取得

//明日
const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);

//明後日
const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 2);

//mday日後の日付を取得(mday = 7)
const mday = 7;
const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + mday);

now.getDate()」に1日(+1)加えることで、
明日を取得できます。
明後日は2日(+2)加えます。
ちなみに昨日を取得する場合、
now.getDate()」に-1日(-1)します。
任意 (mday)の日付を取得するには、
mday = 7」とすることで
1週間後 (7日後)を取得します。

配列として定義した時に悩んだ事

上記のコードを配列として
書いてみました。
無理に配列にしなくても
いいんしゃね?
」という声も
きこえてきそうですが(汗
試してみたかったので、
そしたら悩みまくったという
何とも情けない話です。

配列とは

配列とは、
複数のデーターを一つの変数に
代入する事が出来ます。
変数に数値や文字列を格納する場合は、
通常、1つの変数に1つの値しか
格納できないようです。

// 変数 文字列やオブジェクトを格納できる。
let pet = "cat";

// 配列 1つの変数で複数の値を持つことができる。
let mypets = ["cat", "dog", "bird"];

let(変数)以外にconstを利用した
定数の宣言もできます。
(基本的にconstを使うことがベストですって。)

「変数」と「定数」の違い

どちらも「値を入れておく箱」です。
中の値を変更できるか否かの違いです。
変数は中の値を変更できますが、
定数は中の値を変更できません。

用語意味
変数プログラミング言語における、値を入れておく箱
定数最初に入れた値を後から変更できない変数もどき
「変数」と「定数」の違い

配列と連想配列

配列と連想配列の違いは
「配列は数字」、
「連想配列はkeyと呼ばれる文字列」、
えっ?どういう事?

明確な特徴としては、
配列は [] で囲まれていて、
配列のインデックスは 0 (整数)からはじまる。
連想配列は {} で囲まれており、
この「{}」内で key名と要素(値)を記述する。

// 配列の宣言
let 配列の変数名 = ["値1", "値2", "値3"];

// 連想配列の宣言
let 連想配列の変数名 = {キー名: "値1", キー名: "値2", キー名: "値3"};

配列の作成

配列の作成には
括弧を使ったリテラル記法か、
Arrayオブジェクトを使います。

Arrayオブジェクトを使って
配列をごにょごにょすると、
意図しない結果となってしまう
場合がありますので、
配列を作成するときは
配列リテラルを使用して
作成するのがよいようです。

配列リテラル

配列リテラルとは全体を[]で囲い、
配列の要素をカンマ(,)で区切って
記述することです。
要素には配列に格納する値を記述します。

  const leftime = new Date();
  const toback = new Date(leftime.getFullYear(), leftime.getMonth(), leftime.getDate() + 1);

  function countdown(toback) {
    const now = new Date();
    const differ = toback.getTime() - now.getTime();
    const sec = Math.floor(differ / 1000) % 60;
    const min = Math.floor(differ / 1000 / 60) % 60;
    const hour = Math.floor(differ / 1000 / 60 / 60);
    const sec2 = sec.toString().padStart(2, "0");
    const min2 = min.toString().padStart(2, "0");
    const hour2 = hour.toString().padStart(2, "0");
    const timeid = [hour2, min2, sec2];
    return timeid;
  }

  function setCountDown() {
    const timeidset = countdown(toback);
    const item = `${timeidset[0]}時間${timeidset[1]}分${timeidset[2]}秒`;
    document.getElementById("dayover").innerHTML = item;
    setTimeout(setCountDown, 1000);
  }
  setCountDown();
<div>今日の残り時間は<span id="dayover"></span>です。</div>
return (関数から値を返す)

return」ってなに?
return」 = 返す結果 。

// timeidに配列として定義する
const timeid = [hour2, min2, sec2];

return timeid;   // 配列で返す

例えば、

f(x) = 2x + 5

関数の引数 x に 3 を入れるとします。

f(x) = 2x + 5
↓↓↓
f(3) = 2 × 3 + 5
↓↓↓
f(3) = 6 + 5
↓↓↓
f(3) = 11

f(3) には 11 という値が返って来ます。

function f(x) {
  return 2 * x + 5
};
alert(f(3));

Javascriptの返り値という奴がよくわからないです

function 【1】関数名 (【2】関数の処理に必要な材料) {

 【3】行う処理;

 return【4】
}
  1. 関数名 : 好きな名前を付けられます。
  2. 引数 : 関数に渡す材料です。
  3. 処理 : 関数が行ってくれる一連の処理です。
  4. 戻り値 : 処理した結果、関数が返してくれる内容です。
//  この関数名はnekoで引数はxとy。
function neko(x, y) {
  //  returnでxとyの計算結果を返す。
  return x + y;
}
alert(neko(1, 2));  // 結果 3
テンプレートリテラル

${ ごにゃごにゃ }」これって何?
と思ったのですが、
プレースホルダーというものらしく、
ドル記号と波括弧で示されます。

${ ごにゃごにゃ }」 の中には、
変数や計算式を入れることができます。

しかも
` (バッククオート)」で囲っています。
これは「テンプレートリテラル」と呼ばれ、
文字列として扱いたい箇所を
` (バッククオート)」で囲むことで使えます。
新しく使えるようになった構文のようですが、
便利に使えそうですね。

const item = `${timeidset[0]}時間${timeidset[1]}分${timeidset[2]}秒`;
配列の値を呼び出す

配列の値を呼び出すときは以下のように
[]」の中に呼び出したい
インデックス番号を記述すればOKです。
配列の値は1番目からではなく、
0番目から数えるので注意が必要です。

const x = [0, 1, 2];
 
alert(x[2]); // これは2が出力されます。
引数がない例

以下は関数名だけで、
引数を書かない場合のコードです。

function countdown() {
  const now = new Date();
  const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
  const differ = future.getTime() - now.getTime();
  const sec = Math.floor(differ / 1000) % 60;
  const min = Math.floor(differ / 1000 / 60) % 60;
  const hour = Math.floor(differ / 1000 / 60 / 60);
  const sec2 = sec.toString().padStart(2, "0");
  const min2 = min.toString().padStart(2, "0");
  const hour2 = hour.toString().padStart(2, "0");
  const timeid = [hour2, min2, sec2];
  return timeid;
}

function setCountDown() {
  const timeidset = countdown();
  const item = `${timeidset[0]}時間${timeidset[1]}分${timeidset[2]}秒`;
  document.getElementById("dayover").innerHTML = item;
  setTimeout(setCountDown, 1000);
}
setCountDown();

連想配列 (オブジェクトリテラル)

宣言するときには「{}」を用い、
キー (添え字) に連番ではなく、
好きな名前を付けた配列のことを
「連想配列」といいます。

const myPets = { cat: "きらら", dog: "ジュレ" };  // 変数の宣言と初期化
alert(myPets["cat"]); // []の中にインデックスを指定

alertの引数に「myPets」を渡し、
そのインデックスに "cat" という
文字列を指定したので、
それに対応する「きらら」という名前が
アラートボックスに表示された。

  • オブジェクト (object)
    Javaにおいてはクラス(設計図)のインスタンス(クラスを具現化(実体)したもの)、または配列のこと。
  • リテラル (literal)
    プログラムのソースコードなどで、直接記述される数値や文字列のこと。
for…in

for…in
オブジェクトに含まれる
プロパティ名を取得します。

ただし、
配列での使用は推奨されない

for…in はオブジェクトのプロパティを
反復するために作られたものであり、
インデックスの順序が重要となる
配列の繰り返しには使うべきではありません。

for…in – JavaScript | MDN (mozilla.org)
for( const 変数 in 連想配列 ) { };
const myPets = {
  catF: "きらら",
  catM: "ミント",
  dog: "ジュレ"
};
for (const item in myPets) {
  console.log(item + "は" + myPets[item] + "です。")
}
function countdown() {
  const now = new Date();
  const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
  const differ = future.getTime() - now.getTime();
  const sec = Math.floor(differ / 1000) % 60;
  const min = Math.floor(differ / 1000 / 60) % 60;
  const hour = Math.floor(differ / 1000 / 60 / 60);
  const sec2 = sec.toString().padStart(2, "0");
  const min2 = min.toString().padStart(2, "0");
  const hour2 = hour.toString().padStart(2, "0");
  const timeid = {
    hour: hour2,
    min: min2,
    sec: sec2
  };
  return timeid;
}

function setCountDown() {
  const timeidset = countdown();
  for (const item in timeidset) {
    document.getElementById(item).innerHTML = timeidset[item];
  }
  setTimeout(setCountDown, 1000);
}
setCountDown();
forEach()で配列をループ

forEachは、
配列データに特化した繰り返し処理を
簡単に実行できるメソッドになります。
しかし、連想配列に
forEachは使えない
そうです。

forEachはfor文やwhile文などの
組み込み関数と違い、ただの関数らしく、
Array型の配列では用意されていますが、
連想配列はObject型なので
使えないという事らしいです。

連想配列でもforEachを使うには
連想配列のキー配列から
forEachを呼び出すことで
使えるそうです。
連想配列のキーを
配列として取得するには
Object.keys関数が使えるそうです。

Object.keysとは、
オブジェクトのプロパティの名前の配列を
通常のループで取得するのと同じ順序で返します。

const myPets = {
  catF: "きらら",
  catM: "ミント",
  dog: "ジュレ"
};
Object.keys(myPets).forEach(function (key) {
  console.log(key + "は" + myPets[key] + "です。");
});
function countdown() {
  const now = new Date();
  const future = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1);
  const differ = future.getTime() - now.getTime();
  const sec = Math.floor(differ / 1000) % 60;
  const min = Math.floor(differ / 1000 / 60) % 60;
  const hour = Math.floor(differ / 1000 / 60 / 60);
  const sec2 = sec.toString().padStart(2, "0");
  const min2 = min.toString().padStart(2, "0");
  const hour2 = hour.toString().padStart(2, "0");
  const timeid = {
    hour: hour2,
    min: min2,
    sec: sec2
  };
  return timeid;
}

function setCountDown() {
  const timeidset = countdown();
  Object.keys(timeidset).forEach(function (item) {
    document.getElementById(item).innerHTML = timeidset[item];
  });
  setTimeout(setCountDown, 1000);
}
setCountDown();

forEachの第二引数に
thisオブジェクトを渡す
方法もあり。

function setCountDown() {
  const timeidset = countdown();
  Object.keys(timeidset).forEach(function (item) {
    const main = this[item];
    document.getElementById(item).innerHTML = main;
  }, timeidset);
  setTimeout(setCountDown, 1000);
}
setCountDown();

forEach()の第二引数に渡した値が
ループ内でthisとして使用できるので、
第二引数にオブジェクトを渡す。

const myPets = {
  catF: "きらら",
  catM: "ミント",
  dog: "ジュレ"
};
Object.keys(myPets).forEach(function (key) {
  const val = this[key]; // this は myPets
  console.log(key + "は" + val + "です。");
}, myPets); // 第二引数に myPets を渡す
for…of を使う方法

for…ofを使う場合は、
ループを回す時のkeyが必要なので、
上記の forEachをつかった時と同様に、
Object.keysをつかって
オブジェクトのkey一覧を取得して、
ループを回しています。

const myPets = {
  catF: "きらら",
  catM: "ミント",
  dog: "ジュレ"
};
for (const key of Object.keys(myPets)) {
  console.log( key + "は" + myPets[key] + "です。");
}
function setCountDown() {
  const timeidset = countdown();
  for (const item of Object.keys(timeidset)) {
    document.getElementById(item).innerHTML = timeidset[item];
  }
  setTimeout(setCountDown, 1000);
}
setCountDown();
Object.entries() を使う

Object.entries()とは、
ES2017(ES8) で追加された機能で、
オブジェクトが持つ、
列挙可能なプロパティの
値 (組 [key, value])
の配列を返します。
新しい機能のようですね。

ESとはECMAScript(エクマスクリプト)の略で
JavaScriptの標準規格のことですって。

const myPets = { catF: "きらら", catM: "ミント", dog: "ジュレ" };
// for...of文との組み合わせ
for (const [key, value] of Object.entries(myPets)) {
  console.log( key + "は" + value + "です。");
}
function setCountDown() {
  const timeidset = countdown();
  for (const [key, value] of Object.entries(timeidset)) {
    document.getElementById(key).innerHTML = value;
  }
  setTimeout(setCountDown, 1000);
}
setCountDown();

参考文献

最後に

貴重なお時間を割き、
最後まで
ご高覧いただきまして
有難うございました

配列として定義した時に悩んだ事