Webデザイン学科
授業資料

JavaScript演習
気象庁の天気予報APIとオブジェクト操作

概要解説

気象庁の天気予報 API が、人知れず開放されたようです。(アシアルあんこエデュケーションより)
正式な公開の WebAPI ではなく、サイト内部で利用されているデータではありますが、
「政府標準利用規約に準拠してご利用いただける」との情報が気象庁の中の人から出ました。

使えるうちに、気象庁の API を利用して、天気予報アプリを作っていきたいと思います。
Web アプリ制作の「Youtube Date API」と被る部分がありますが、こちらで先に実装することで慣れていきます。

内容

  • JavaScript クイズ ②
  • 気象庁 天気予報 API
  • オブジェクトの操作
  • for…in 文

JavaScript クイズ

15 分以内に回答して、送信してください。

気象庁 天気予報 API

上記にあるように、気象庁の天気予報の API が非公式ですが、公開されています。
なぜ、投稿者が歓喜しているのかというと、いままで天気予報のアプリを使う場合は、
信憑性が怪しい海外の天気予報データや、有料の天気予報 API を利用しなければいけませんでした。
これが、日本の国家機関という、最も信憑性の高い情報を無料で利用できるからです。
ただし、非公式ということで、突然閉鎖してしまう可能性もありますので、使えるうちに作品を作りたいと思います。

エンドポイント

Web API におけるエンドポイントは、API に アクセスするための URI を指します。
基本的には、URI が「リソース」を指すものであり、
URI と HTTP メソッドの組み合わせで処理の内容を表すのが良い設計であるとされています。

  • 天気予報の概要(今日・明日※48 時間)を取得するエンドポイント
    https://www.jma.go.jp/bosai/forecast/data/overview_forecast/都道府県コード + 0000.json
  • 天気予報(今日・明日※48 時間・週間)を取得するエンドポイント
    https://www.jma.go.jp/bosai/forecast/data/forecast/都道府県コード + 0000.json

都道府県コード及び市区町村コード

都道府県コード及び市区町村コードは、情報処理の効率化と円滑化に資するため、コード標準化の一環として、
総務省(当時:自治省)が昭和 43 年に全国の都道府県及び市区町村のコードを設定したものです。
以来、変更が生じた都度、更新を行っています。

愛知県の天気予報の概要を取得

愛知県の天気予報の概要(今日・明日・明後日)を取得して console に表示してみます。
まず、https://www.jma.go.jp/bosai/forecast/data/overview_forecast/230000.jsonをブラウザのアドレスバーにコピペして展開します。
上手く見えない場合は、Chrome の拡張機能JSON Viewerをインストールしてください。

この json を Ajax で取得すれば良いので、fetch()を利用します。

<script>
	//東海4県のコード番号をオブジェクトの配列にしておきます。
	const codeNums = [{ "愛知県": 23 }, { "岐阜県": 21 }, { "三重県": 24 }, { "静岡県": 22 }];
	//テンプレートリテラルでconst urlに代入します。
	const url = `https://www.jma.go.jp/bosai/forecast/data/overview_forecast/${codeNums[0]['愛知県']}0000.json`;

	fetch(url)
		.then(function (response) {
			return response.json();
		})
		.then(function (weather) {
			console.log(weather);
		});
</script>

ブラウザに表示してみます。
fetch()部分に書き加えます。

fetch(url)
	.then(function (response) {
		return response.json();
	})
	.then(function (weather) {
		console.log(weather);
		for (const key in weather) {
			const text = document.createElement('p');
			document.body.appendChild(text).innerHTML = key + ':' + weather[key];
		}
	});

同じように、愛知県の天気予報(今日・明日※48 時間・週間)を取得できます。
https://www.jma.go.jp/bosai/forecast/data/forecast/230000.json

const weekUrl = `https://www.jma.go.jp/bosai/forecast/data/forecast/${codeNums[0]['愛知県']}0000.json`;

fetch(weekUrl)
	.then((response) => response.json())
	.then((data) => console.log(data));

天気予報(今日・明日※48 時間・週間)の json を扱うために、json データ(オブジェクト)の操作方法を習得していきます。
新しいファイルを作成し、アロー関数、オブジェクトの操作、for…in 文などを復習していきましょう。

アロー関数

アロー関数式は、従来の関数の宣言・関数式の簡潔な代替構文ですが、制限があり、すべての場面で使用することができるわけではありません。

従来の関数とアロー関数の比較

「従来の関数」を分解して、最もシンプルな「アロー関数」に段階的に変えていきましょう。

// 伝統的な関数
function (a){
  return a + 100;
}

// アロー関数に分解

// 1. "function" という語を削除し、引数と本体の開始中括弧の間に矢印を配置する
(a) => {
  return a + 100;
}

// 2. 本体の中括弧を削除と "return" という語を削除 -- return は既に含まれています。
(a) => a + 100;

// 3. 引数の括弧を削除
a => a + 100;

例えば、複数の引数や引数なしの場合、引数の周りの括弧を入れなおす必要があります。

// 従来の関数
function (a, b){
  return a + b + 100;
}

// アロー関数
(a, b) => a + b + 100;

// 従来の関数 (引数なし)
let a = 4;
let b = 2;
function (){
  return a + b + 100;
}

// アロー関数 (引数なし)
let a = 4;
let b = 2;
() => a + b + 100;

同様に、本文に処理の追加の行が必要な場合は、中括弧に加えて “return” を入れなおす必要があります。

// 従来の関数
function (a, b){
  let chuck = 42;
  return a + b + chuck;
}

// アロー関数
(a, b) => {
  let chuck = 42;
  return a + b + chuck;
}

名前付き関数については、変数のようにアロー関数式を扱います。

// 従来の関数
function bob(a) {
	return a + 100;
}

// アロー関数
let bob = (a) => a + 100;

【注意】 アロー関数は自身の this を持ちません。

アロー関数は自身の this を持ちません。Object.defineProperty()を使った他の例で

var obj = {
	a: 10
};

Object.defineProperty(obj, 'b', {
	get: () => {
		console.log(this.a, typeof this.a, this); // undefined 'undefined' Window {...} (or the global object)
		return this.a + 10; // represents global object 'Window', therefore 'this.a' returns 'undefined'
	}
});

=>で表示されている JavaScript は、function()をアロー関数で省略しています。
自分でも記述できるように、まずは、イベント時の関数に使っていくなど徐々に取り入れても良いですね。

オブジェクトの操作と非同期

JavaScript のオブジェクトは、名前と値のペアの集合です。
名前と値のペアをプロパティと呼びます。
プロパティ名は、識別子(x や y など)、文字列値、数値のいずれか、プロパティ値は、任意の値やオブジェクトが使用可。

オブジェクトの基本

//オブジェクト
{プロパティ:プロパティ値,プロパティ:プロパティ値,}

let user = {
	// オブジェクト
	name: 'John', // キー "name" に値 "John" が格納される
	age: 30 // キー "age" に値 30 が格納される
};

【演習・復習】オブジェクトを操作してみよう

  1. 変数 hashira_list に下記の表から”キー”に柱、“値”に氏名を設定し、恋柱の氏名を console に表示させてください。
  2. 水柱の氏名を冨岡義勇に書き換えて、console に表示させてください。
氏名
水柱鱗滝左近次
蟲柱胡蝶しのぶ
炎柱煉獄杏寿郎
音柱宇髄天元
恋柱甘露寺蜜璃
岩柱悲鳴嶼行冥
霞柱時透無一郎
蛇柱伊黒小芭内
風柱不死川実弥

オブジェクトのループ

for 文

オブジェクトでも for 文が利用できますが、Object.keys()もしくは、Object.valus()を取得するひと手間必要です。
key や values は配列で取得できますので、それを利用して for 文でループします。

const name_object = { first: '松田', second: '田中', third: '中山', fourth: '山本', fifth: '本田' };
const keys = Object.keys(name_object); //first,second,…
const values = Object.values(name_object); // 松田,田中,…
console.log(keys, values);

//Object.keysを使った場合
const keys = Object.keys(name_object);
for (let i = 0; i < keys.length; i++) {
	console.log(i + 1 + '人目は' + name_object[keys[i]]);
}

//Object.valuesを使った場合
const values = Object.values(name_object);
for (let i = 0; i < values.length; i++) {
	console.log(i + 1 + '人目は' + values[i]);
}

for…in 文

for…in 文は、オブジェクトの要素に対して繰り返し処理を行う時に使います。

const fruits = { apple: 'りんご', mikan: 'みかん', painapple: 'パイナップル', mango: 'マンゴー' };

for (const key in fruits) {
	console.log(`キー[${key}]値:[${fruits[key]}]`);
}

注意、for…in 文では、取得できる順番は担保されません。

配列に入ったオブジェクト

オブジェクトを配列に入れることで、複数のオブジェクトを扱うことができます。

const fruitslocal = [
	{ apple: '青森', mikan: '愛媛', strawberry: '三重', grape: '山梨' },
	{ apple: '福岡', mikan: '静岡', strawberry: '愛知', grape: '群馬' },
	{ apple: '高知', mikan: '宮崎', strawberry: '北海道', grape: '岩手' }
];
//愛知が欲しい場合
console.log(fruitslocal[1].strawberry);
//もしくは
console.log(fruitslocal[1]['strawberry']);

//配列に入っているので、for文で取得できる。
for (let i = 0; i < fruitslocal.length; i++) {
	console.log(fruitslocal[i]);
}

プロパティの値を取得する場合、

for (let i = 0; i < fruitslocal.length; i++) {
	console.log(fruitslocal[i].apple);
	console.log(fruitslocal[i].mikan);
	console.log(fruitslocal[i].strawberry);
	console.log(fruitslocal[i].grape);
}

//for文とfor...in文を組み合わせれば
for (let i = 0; i < fruitslocal.length; i++) {
	for (const property in fruitslocal[i]) {
		console.log(`${property}:${fruitslocal[i][property]}`);
	}
}

JSON

このオブジェクトの記法を利用したものが、JSON(JavaScript Object Notation)と呼ばれ、
さまざまなデータのやり取りに利用されています。
天気予報のデータも JSON で送られていますので、天気予報の概要(今日・明日・明後日)では for..in 文で取得しています。
天気予報(今日・明日・明後日・週間)では、複数組み合わせて必要な値を取得します。

【演習】for…in 文で JSON の値取得

下記の const npb から for 文と for…in 文を使ってすべての要素を取得して console に表示させてください。

const npb = [{"team": "広島東洋カープ", "win": 12, "lose": 6, "rate": .667},
    {"team": "讀売ジャイアンツ", "win": 13, "lose": 7, "rate": .650},
    {"team": "中日ドラゴンズ", "win": 10, "lose": 7, "rate": .588},
    {"team": "東京ヤクルトスワローズ", "win": 10, "lose": 9, "rate": .526},
    {"team": "横浜DeNAベイスターズ", "win": 6, "lose": 9, "rate": .400},
    {"team": "阪神タイガーズ", "win": 3, "lose": 16, "rate": .158}
]
//for文とfor...in文
for (let i = 0; i < npb.length; i++) {
	for (const key in npb[i]) {
		console.log(npb[i][key]);
	}
}

for…of 文

for…of 文も使ってみましょう。

const array1 = ['a', 'b', 'c'];

for (const element of array1) {
	console.log(element);
}

上記の const npb から for 文と for…in 文を使ってすべての要素を取得して console に表示させてください。

<table>
	<thead>
		<tr>
			<th>順位</th>
			<th>チーム</th>
			<th>勝数</th>
			<th>負数</th>
			<th>勝率</th>
		</tr>
	</thead>
	<tbody>
		<tr></tr>
		<tr></tr>
		<tr></tr>
		<tr></tr>
		<tr></tr>
		<tr></tr>
	</tbody>
</table>
const tablerow = document.querySelectorAll('tbody tr');
//for of文ではなく、for文で取得することで添字を取得できます。
for (let i = 0; i < npb.length; i++) {
	tablerow[i].innerHTML = `<td>${i + 1}位</td>`;
	for (const key in npb[i]) {
		console.log(npb[i][key]);
		const tabledata = document.createElement('td');
		tabledata.innerHTML = npb[i][key];
		tablerow[i].appendChild(tabledata);
	}
}

//もしくは、npb.entries()で添字と値を取得できます。
for (const [i, value] of npb.entries()) {
	console.log(i, value);
	tablerow[i].innerHTML = `<td>${i + 1}位</td>`;
	for (const key in npb[i]) {
		console.log(npb[i][key]);
		const tabledata = document.createElement('td');
		tabledata.innerHTML = npb[i][key];
		tablerow[i].appendChild(tabledata);
	}
}

//jQueryのeachと無駄にアロー関数を使って
$.each(npb, (index, obj) => {
	$('tbody tr')
		.eq(index)
		.append(`<td>${index + 1}位</td>`);
	$.each(obj, function (key, value) {
		$('tbody tr').eq(index).append(`<td>${value}</td>`);
	});
});

2022-04-19
Hideo kawaguchi