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

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

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

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

Q&A

解決済

3回答

2477閲覧

変数のスコープがfetchの中ので変わってしまう。

NCC1701

総合スコア1680

JavaScript

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

0グッド

0クリップ

投稿2019/11/04 08:37

前提・実現したいこと

住所から郵便番号を取得するためのスクリプトを書いています。該当するデータを配列変数citiesに追加していくだけなのですが、後記のスクリプトだと、ループから出たら配列が空になってしまいます。

変数のスコープが合っていないようなのですが、どのように解決したら良いかわかりません。

発生している問題・エラーメッセージ

#1 では変数citiesは最終的に長さ3の配列になります。しかし#2ではからになってしまいます。

該当のソースコード

javascript

1const apiUrl = 'http://zipcoda.net/api?address=' 2let targetUrl 3let address 4 5let prefectures = ['東京都', '広島県'] 6address = '府中市緑町1-1-1' 7 8let cities = new Array() 9for (let city of prefectures) { 10 targetUrl = apiUrl + city + address 11 fetch(targetUrl) 12 .then(response => response.json()) 13 .then(json => { 14 cities = cities.concat(json.items) 15 console.log(cities) // #1 16 }); 17} 18 19console.log(cities) // #2

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

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

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

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

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

guest

回答3

0

console.log()で出力される順番は#2,#1 となっていませんか?

Ajaxは非同期実行であるため、コードが上から順番に流れるわけではありません。処理を投げて返ってくる間にそのスコープ外の処理が流れてしまうこともあります(というか大抵スコープ内の処理のほうが後になります)。

投稿2019/11/04 08:50

m.ts10806

総合スコア80850

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

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

0

ベストアンサー

こんにちは。

#1 では変数citiesは最終的に長さ3の配列になります。しかし#2ではからになってしまいます。

という結果で問題はないのではと思います。ログが出力される順番をみると、

console.log(cities) // #2

によって、空の配列が表示されるのが(時間的に)先で、

console.log(cities) // #1

が2回表示されるほうが後になっていると思われますが、いかがでしょうか?留意すべきことは

console.log(cities) // #2

が、ソースコードの中で一番下の行に書いてあるからといって、時間的に最後に実行されるわけではない、ということです。

参考になれば幸いです。

追記

ご理解の参考になるとよいのですが、擬似的なAPIのつもりのfetchDummy という関数を自作して、レスポンスを返すまで時間を、東京都の場合は5秒、広島県の場合は2秒待たせるようにして、これで、ご質問に挙げられているコードの fetch を置き換えたものが以下です。console.log で出力する情報も追加しています。

このサンプルでは、APIにリクエストを送ってから、レスポンスが返ってくるまでには一般に時間がかかることを模しており、それを待たずに#2 のログが出力されること、および、forループの順序で、先にリクエストが送られるのは東京都のほうであっても、cities には、先にレスポンスが返ってくる広島県の items が、先に追加されていることが分かると思います。

投稿2019/11/04 08:50

編集2019/11/04 14:15
jun68ykt

総合スコア9058

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

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

NCC1701

2019/11/04 08:58

なんと、非同期実行という初歩的なことを失念していたのですね。猛省です。 ありがとうございました。
jun68ykt

2019/11/04 14:16

どういたしまして。蛇足かもしれませんが、回答に追記しました。参考になれば幸いです。
guest

0

「アロー関数は、宣言した時点で this を確定する」と言うような記事を読んだことがあります。
// #1 の結果を得る関数を 変数 cities と同スコープで宣言してみるとどうでしょうか。

javascript

1let cities = new Array() 2let setResult = json => { 3 cities = cities.concat(json.items) 4 console.log(cities) // #1 5} 6 7for (let city of prefectures) { 8 targetUrl = apiUrl + city + address 9 fetch(targetUrl) 10 .then(response => response.json()) 11 .then(setResult); 12} 13console.log(cities) // #2

投稿2019/11/04 08:50

AkitoshiManabe

総合スコア5432

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

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

AkitoshiManabe

2019/11/04 08:52

単に実行順ですね。自分でマイナス評価つけたいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問