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

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

ただいまの
回答率

90.51%

  • JavaScript

    20399questions

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

letとconstの巻き上げは起こりますか?

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 5
  • VIEW 1,397

makkuro

score 14

Qiitaのvar/let/constの使い分けのメモという記事を読みながら、varletconstの挙動を確かめてみました。

当該記事には、

var : 巻き上げは起きる
let : 巻き上げは起きる
const : 巻き上げは起きる

と書かれています。

しかし、varで巻き上げが起こることは確認したのですが、letconstについて、自分では巻き上げが起こることは確認できませんでした。

確認に使ったコードを以下に書きます。


varの場合

const show = () => {
  console.log(str)
  var str = 'hello'
  console.log(str)
}
show()

/* 出力
undefined
hello
*/

letの場合

const show = () => {
  console.log(str)
  let str = 'hello'
  console.log(str)
}
show()

/* 出力
  console.log(str)
              ^
ReferenceError: str is not defined
*/

constの場合

const show = () => {
  console.log(str)
  const str = 'hello'
  console.log(str)
}
show()

/* 出力
  console.log(str)
              ^
ReferenceError: str is not defined
*/

letconstにもvarと同様に巻き上げが起こるのであれば、上記3つの出力結果はいずれも

undefined
hello


になると思います。

実行環境はVSCodeです。

もしかしたら巻き上げを誤解している気がしたので質問させていただきました。
よろしくお願いします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+20

letconstでもある意味では巻き上げは発生します。下記のNOTEに詳しく書いています。

13.3.1 Let and Const Declarations - ECMAScript® 2018 Language Specification

しかし、varや関数宣言とは巻き上げ時の動作が異なります。

巻き上げと言ったとき、大きく二つの動作が行われます。

  1. 環境レコード生成時にその環境レコード内に変数も作成すること。
  2. 変数を作成する時に何らかの値(undefinedや関数そのもの等)を代入(assigne)すること。

var、関数宣言、関数の仮引数は1.と2.の両方の動作を行いますが、letconstは1.の動作のみを行い、変数を「何も代入されていない状態」にします。この「何も代入されていない状態」はundefinedが代入された状態とは異なる状態です。そして、「何も代入されていない状態」の変数を参照すると、ReferenceErrorが発生するようになっています。

つまり、1.の意味での巻き上げはletconstでも発生するのですが、1.と2.の両方の意味での巻き上げは発生しないと言うことです。

本当に一切の巻き上げが発生しないのは非strictモードでのvar等を使用しない代入です。この場合は、グローバル環境レコード(グローバルオブジェクトと同一)にグローバル変数(グローバルオブジェクトのプロパティ)が作られますが、巻き上げが起きるわけでは無くて、まさしく、代入時にグローバル変数(グローバルオブジェクトのプロパティ)が作られます。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/15 07:43

    自分は「変数の種類による違い」と考えてしまったのですが、むしろ巻き上げ動作の違いと認識すべきなのですね!ヘンテコな回答をしてしまいました・・・

    キャンセル

  • 2019/05/15 13:53

    var、let、constいずれも環境レコード内に変数を作成(巻き上げ)しているが、varはundefinedというプリミティブ値を代入している、letとconstはundefinedを代入しないのでエラーになる。ということだったんですね。undefinedを代入という感覚がなかったので、とてもしっくりきました。分かりやすい回答をありがとうございました。

    キャンセル

  • 2019/05/15 22:16

    > KSwordOfHasteさん

    いいえ、KSwordOfHasteさんの回答が大きく間違っているという訳ではないと思います。キーワードの違いが、巻き上げ時の処理の違いになり、結果として、宣言文の前にアクセスしたときの動作の違い似なるのですから。

    私も例文を出した方が良かったのですが、すぐに思いつかなかった(そして、もうでかける時間だった)ので、何も出せませんでした。KSwordOfHasteさんの回答の例がとてもシンプルに巻き上げの現象を説明していると思います。より細かい解説でも書こうかなと思ったのですが、環境レコードの話から、スコープチェーンやクロージャーの説明まで一通りしないといけないから、なかなか難しいものです。何かの機会があったら、一つ記事でも書いてみたいところですね。

    キャンセル

  • 2019/05/16 11:00

    コメントありがとうございます。

    raccyさん回答でいろいろ気づきがありましたが、結局のところECMAScriptの言語仕様書とMDNの解説のどちらで把握する方がよいかがポイントであった気がします。どちらがよいかは自明ですね!

    「より細かい解説」には大変興味があります。アマチュアの自分などは自らに対し「知りたいなら自分で知る努力を」と心がけているつもりではありますが、先人の知識の蓄積に近づくのは容易ではないのでよい解説には常に飢えてます。ここは勝手に「ひそかに期待」させていただこうと思います。

    キャンセル

+7

巻き上げと変数の種類による挙動の違いを混同しておられると思います。

2つ目の例で述べますと

var str = "foo"

function show() {
  console.log(str)  // (A)
  let str = 'hello'
  console.log(str)  // (B)
}

show()


もし巻き上げが起きないなら(A)ではfooが印字されることになりますが実際はstrが巻き上げのためshowのローカル変数であるとみなされます。それゆえ(A)の結果が"foo"にはならないのです。これが「巻き上げ」による効果です。

振る舞いがundefinedと例外という違いとなって現れたのは巻きあげの有無ではなく変数の種類による違いです。

  • varによる変数
    有効スコープ内において最初の代入前にアクセスするとundefinedという結果になります。

  • let/constによる変数
    有効スコープ内において最初の代入前にアクセスすると例外ReferenceErrorがスローされます。

参考:
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/var
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/let

JavaScriptに詳しくないのですがvarの振る舞いは従来の仕様の互換性のために定められたものではないかと想像します。「undefindになってくれてありがたい」かといえば「ありがたくないことの方が多い」と思います。どちらかといえばlet/constの振る舞いの方がありがたいと思いませんか?自分はそう思います。多くのプログラマーもそう思ったのではないでしょうか?それゆえ新しい仕様のlet/constでは代入前の仕様がかわったのではないかと思います。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/05/15 11:18

    横槍失礼します。
    >「undefindになってくれてありがたい」かといえば「ありがたくないことの方が多い」と思います。どちらかといえばlet/constの振る舞いの方がありがたいと思いませんか?

    これ禿同ですね。
    変数宣言がないなら、無いというエラーの方がわかりやすくていいですね。(エラーがあるなら処理止めて欲しい)
    ただ、JSの登場当初、Web上のJavaScriptの役割上、エラーで処理を止めない方が都合がいい時代だったのかもしれません。
    現代は、Webだけではないですし、Web上でもJSの役割が変わってきているので、より他の言語と同じ仕様が求められるようになったのかもしれません。

    キャンセル

  • 2019/05/15 13:16

    コメントありがとうございます。
    > Web上でもJSの役割が変わってきている
    自分はJavaScriptの成長を近年になるまで知らずにいて、このサイトを通じて学ぶ機会を得、遅まきながらWebやJSに興味を持ちました。イマイチな回答が多い気がする自分だけに、ここはそうとかここは違うよとかいうコメントをいただくと大変ありがたいです。ありがとうございました。

    キャンセル

  • 2019/05/15 13:59

    たしかに、undefinedを気づかないうちに代入されるぐらいなら、エラーになってもらった方がありがたいですね。プログラマー視点の考えも織り交ぜていただいて、raccyさんの回答と一緒に読んでとても分かりやすかったです。varではなくletとconstを使っていこうと思います。分かりやすい回答をありがとうございました。

    キャンセル

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

  • JavaScript

    20399questions

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