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

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

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

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

Q&A

解決済

2回答

1415閲覧

javascriptで宣言前の関数がどうして実行されるのかが分かりません

tanakashouzoux

総合スコア52

JavaScript

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

0グッド

0クリップ

投稿2020/06/01 00:03

下記の「checkResult();」が「function checkResult(){};」よりも前に記述されているのに、どうして実行されているのかがよく分かりません。
スコープが違うので「巻き上げ」では無いと思い、他に思いつくことがありません。
どなたか詳しい方ご教示頂けないでしょうか?

javascript

1'use strict'; 2 3{ 4 class Panel { 5 constructor() { 6 const section = document.createElement('section'); 7 section.classList.add('panel'); 8 9 this.img = document.createElement('img'); 10 this.img.src = this.getRandomImage(); 11 12 this.timeoutId = undefined; 13 14 this.stop = document.createElement('div'); 15 this.stop.textContent = 'STOP'; 16 this.stop.classList.add('stop'); 17 this.stop.addEventListener('click', () => { 18 clearTimeout(this.timeoutId); 19 20 panelsLeft--; 21 22 if (panelsLeft === 0) { 23 checkResult(); 24 } 25 }); 26 27 section.appendChild(this.img); 28 section.appendChild(this.stop); 29 30 const main = document.querySelector('main'); 31 main.appendChild(section); 32 } 33 34 getRandomImage() { 35 const images = [ 36 'img/seven.png', 37 'img/bell.png', 38 'img/cherry.png', 39 ]; 40 return images[Math.floor(Math.random() * images.length)]; 41 } 42 43 spin() { 44 this.img.src = this.getRandomImage(); 45 this.timeoutId = setTimeout(() => { 46 this.spin(); 47 }, 50); 48 } 49 } 50 51 function checkResult() { 52 if (panels[0].isUnmatched(panels[1], panels[2])) { 53 panels[0].unmatch(); 54 } 55 if (panels[1].isUnmatched(panels[0], panels[2])) { 56 panels[1].unmatch(); 57 } 58 if (panels[2].isUnmatched(panels[0], panels[1])) { 59 panels[2].unmatch(); 60 } 61 } 62 63 const panels = [ 64 new Panel(), 65 new Panel(), 66 new Panel(), 67 ]; 68 69 let panelsLeft = 3; 70 71 const spin = document.getElementById('spin'); 72 spin.addEventListener('click', () => { 73 panels.forEach(panel => { 74 panel.spin(); 75 }); 76 }); 77}

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

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

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

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

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

guest

回答2

0

ベストアンサー

スコープが違うので「巻き上げ」では無いと思い

いえ、クラスの中もcheckResultが宣言されたスコープの内側ですので、巻き上げは有効です。

投稿2020/06/01 00:10

maisumakun

総合スコア145121

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

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

maisumakun

2020/06/01 00:11

仮に巻き上げが効いていないとしたら、変数名自体が見つからずReferenceErrorになるはずです。
tanakashouzoux

2020/06/01 00:14

何度もご指導ありがとうございますm(__)m 私のスコープに対する認識が甘いのだと思います(´;ω;`) 今回のcheckResultも巻き上げと考えて宜しいのでしょうか??
tanakashouzoux

2020/06/01 00:27

何度も本当にありがとうございますm(__)m ちなみに「クラスの中もcheckResultが宣言されたスコープの内側」とのことですが、これは「checkResultが宣言されたスコープの内側にクラスがある」ということなのでしょうか??
maisumakun

2020/06/01 00:27

そのとおりです。
tanakashouzoux

2020/06/01 00:43

何度も迅速にお答え頂きありがとうございますm(__)m 大変恐縮なのですが、「checkResultが宣言されたスコープの内側にクラスがある」とは「checkResult関数の中身にインスタンスが出てくるから、インスタンス元のクラスに記述されているcheckResult();が実行される」ということなのでしょうか?? また、今気づいたのですが、checkResult関数内のpanels[ ]も「巻き上げ」が行われているのでしょうか? 沢山質問してしまい本当に恐縮なのですが、宜しければご回答頂けると幸いです
maisumakun

2020/06/01 00:48 編集

> 「checkResult関数の中身にインスタンスが出てくるから、インスタンス元のクラスに記述されているcheckResult();が実行される」ということなのでしょうか?? 違います。「全体を覆う{...}のブロックの中にcheckResultもクラスもある」ということです。 > checkResult関数内のpanels[ ]も「巻き上げ」が行われているのでしょうか? そうですね。ただし、constの巻き上げはまた特殊で、変数への代入が実行される前に呼ぶとReferenceErrorを起こします(関数宣言の巻き上げは位置を気にせず呼ぶことができます)。 https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let#Temporal_dead_zone (letについての説明ですが、constでも同じです)
tanakashouzoux

2020/06/01 01:16

何度も本当にありがとうございますm(__)m 「全体を覆う{...}のブロックの中にcheckResultもクラスもある」ということ、認識できました!! 私は{}をブロックスコープと呼び、{}の中の物は{}の外からは使えないと覚えていたのですが、{}の外の物は{}の中から使う事が可能なのでしょうか??
maisumakun

2020/06/01 01:21

> {}の外の物は{}の中から使う事が可能なのでしょうか?? はい、JavaScriptでは外側で宣言されたものは(内側のものと名前が衝突しない限り)アクセス可能です。
tanakashouzoux

2020/06/01 01:41

すいませんなんだか考えてる内に頭が混乱してしまいまして・・・ 「外側で宣言されたものは(内側のものと名前が衝突しない限り)アクセス可能」とのことですが、これはその記述が出るより前に宣言されたものでアクセス可能で、それ以外は巻き上げのみ後に記述されていても可能ということでよろしいでしょうか? また、巻き上げをググったところ、同じ{}内でのみ可能とあったのですがこれは間違っているのでしょうか?
maisumakun

2020/06/01 01:47 編集

> これはその記述が出るより前に宣言されたものでアクセス可能で、それ以外は巻き上げのみ後に記述されていても可能ということでよろしいでしょうか? すみません、質問の意味が取れません。 > 巻き上げをググったところ、同じ{}内でのみ可能とあったのですがこれは間違っているのでしょうか? 正しいです。関数を宣言したブロックの外側はスコープ外ですので、巻き上げも当然起きません。
tanakashouzoux

2020/06/01 02:02

こんな質問もまともに出来ない人間にも真摯に回答頂き本当にありがとうございますm(__)m すいません再度質問させて頂きますと、「stop」をクリックした時「checkResult();」により「checkResult関数」が実行されると思うのですが、呼び出す「checkResult関数」が「checkResult();」がある{}と同じ{}の中にないので巻き上げが行われず、さらに「checkResult関数」が「checkResult();」より前に書かれていないので実行されないと思ったのですが、どうして実際には実行されるのでしょうか?
maisumakun

2020/06/01 02:04

> 呼び出す「checkResult関数」が「checkResult();」がある{}と同じ{}の中にないので巻き上げが行われず いえ、同じ{}の中にあります。
tanakashouzoux

2020/06/01 02:16

何度も何度もご回答頂きありがとうございますm(__)m 「checkResult関数」と「checkResult();」は同じ{}の中にあるのですか?! 私には 「checkResult();」はconstructor(){}の中のif () {}の中にポツンと1つだけあって、「checkResult関数」とは違う{}の中にある様な気がするのですが、この認識はどの辺りが間違っているのか御指導頂けないでしょうか? class Panel{}と「checkResult関数」が同じ{}の中にあるのは理解しおりますm(__)m
maisumakun

2020/06/01 02:19 編集

はい、checkResultが宣言されたブロックの内側にcheckResult();の行があります。何段かネストされた{}がありますが、「同じ{}の中」であることに変わりはありません。
tanakashouzoux

2020/06/01 02:48

その様に考えるんですね! すごく納得いきました!!! 本当にありがとうございます!!!!!!!
tanakashouzoux

2020/06/01 05:12 編集

すいません再度疑問が出てきたので質問させてくださいm(__)m maisumakunさんに以前の別な質問で「関数は同じスコープ内にであれば実行後に宣言することも可能」と教えて頂いたのですが、今回の様に何段もネストされた{}の中にあっても大丈夫という事は「異なるスコープにそれぞれ関数とその関数を実行する部分が存在する」という事はあり得るのでしょうか? 何段もネストされた{}の中にあっても大丈夫という事は元を辿れば皆同じグローバルスコープ?内に存在する気がしたのですが、この考えはやはり間違っているのでしょうか?
maisumakun

2020/06/01 05:25

> 「異なるスコープにそれぞれ関数とその関数を実行する部分が存在する」という事はあり得るのでしょうか? 今まで書いたように、「内側のスコープは外側のスコープを含む」と考えてください。全く別なスコープで書いたものは、(完全にグローバルなものを除けば)参照できません。 (ここまですっかり忘れていましたが、中括弧でスコープが切れるのは、let/constについてだけです。varやfunctionは関数スコープです)
tanakashouzoux

2020/06/01 05:33

何度も何度も本当にありがとうございます!!! 関数文に関しては「内側のスコープは外側のスコープを含む」と考え、中括弧を跨いで使えないのは「let/const」なのですね! ちなみに全く別なスコープとはどの様な場合があるのでしょうか? 例えば違うファイルで書かれた2つのjavascriptファイルとかそういったことなのでしょうか?
maisumakun

2020/06/01 05:36

function outer(){ function a(){} }のような場合、aをouterの外から使うことはできません。
tanakashouzoux

2020/06/01 05:42

詳しい例をありがとうございますm(__)m function a(){}もネストされていて元を辿ると同じスコープの様な気がするのですが、これは前回のネストを辿る文脈とは異なるのでしょうか?
maisumakun

2020/06/01 05:43

外側から内側にはたどりません。
tanakashouzoux

2020/06/01 05:48

くだらない質問をすいませんでした(´;ω;`) 私がバカでした こんな何も分からない人間にも優しく何度でも答えて下さり本当にありがとうございましたm(__)m 1人で勉強していて分からない事だらけで困っていたので本当に救われました! ありがとうございます!!!
guest

0

checkResultが実行されているPanelが実行(インスタンス化)されているのはcheckResult定義後になっているからではないでしょうか。

ただ、もっとミニマムコードで試してみるとわかるのですが、これでも実行できます。

js

1a(); 2function a(){} 3

投稿2020/06/01 00:06

編集2020/06/01 00:09
m.ts10806

総合スコア80765

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

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

tanakashouzoux

2020/06/01 00:16

わざわざご回答頂きありがとうございます! コードの流れとしてはnew Panel()まで上から下へと進んで、new Panel()に到達したら各インスタンスにPanelクラスに書かれものが実装されると考えて宜しいのでしょうか?
m.ts10806

2020/06/01 00:40

同じスコープ内なので、結局は巻き上げですね。
tanakashouzoux

2020/06/01 05:34

何度もご丁寧にありがとうございます! 巻き上げ、もっと勉強したいと思います!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問