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

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

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

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

Q&A

解決済

2回答

2809閲覧

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

makkuro

総合スコア57

JavaScript

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

7グッド

5クリップ

投稿2019/05/14 20:25

編集2019/05/15 04:50

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

当該記事には、

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

と書かれています。

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

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


varの場合

JavaScript

1const show = () => { 2 console.log(str) 3 var str = 'hello' 4 console.log(str) 5} 6show() 7 8/* 出力 9undefined 10hello 11*/

letの場合

JavaScript

1const show = () => { 2 console.log(str) 3 let str = 'hello' 4 console.log(str) 5} 6show() 7 8/* 出力 9 console.log(str) 10 ^ 11ReferenceError: str is not defined 12*/

constの場合

JavaScript

1const show = () => { 2 console.log(str) 3 const str = 'hello' 4 console.log(str) 5} 6show() 7 8/* 出力 9 console.log(str) 10 ^ 11ReferenceError: str is not defined 12*/

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

undefined hello

になると思います。

実行環境はVSCodeです。

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

mar-kn, umaru, rkojima, Y.H., x_x, de9👍を押しています

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

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

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

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

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

guest

回答2

0

ベストアンサー

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/14 22:28

raccy

総合スコア21737

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

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

KSwordOfHaste

2019/05/14 22:43

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

2019/05/15 04:53

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

2019/05/15 13:16

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

2019/05/16 02:00

コメントありがとうございます。 raccyさん回答でいろいろ気づきがありましたが、結局のところECMAScriptの言語仕様書とMDNの解説のどちらで把握する方がよいかがポイントであった気がします。どちらがよいかは自明ですね! 「より細かい解説」には大変興味があります。アマチュアの自分などは自らに対し「知りたいなら自分で知る努力を」と心がけているつもりではありますが、先人の知識の蓄積に近づくのは容易ではないのでよい解説には常に飢えてます。ここは勝手に「ひそかに期待」させていただこうと思います。
guest

0

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

2つ目の例で述べますと

js

1var str = "foo" 2 3function show() { 4 console.log(str) // (A) 5 let str = 'hello' 6 console.log(str) // (B) 7} 8 9show()

もし巻き上げが起きないなら(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/14 21:51

KSwordOfHaste

総合スコア18400

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

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

miyabi_takatsuk

2019/05/15 02:18

横槍失礼します。 >「undefindになってくれてありがたい」かといえば「ありがたくないことの方が多い」と思います。どちらかといえばlet/constの振る舞いの方がありがたいと思いませんか? これ禿同ですね。 変数宣言がないなら、無いというエラーの方がわかりやすくていいですね。(エラーがあるなら処理止めて欲しい) ただ、JSの登場当初、Web上のJavaScriptの役割上、エラーで処理を止めない方が都合がいい時代だったのかもしれません。 現代は、Webだけではないですし、Web上でもJSの役割が変わってきているので、より他の言語と同じ仕様が求められるようになったのかもしれません。
KSwordOfHaste

2019/05/15 04:16

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

2019/05/15 04:59

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問