#なぜ、巻き上げるのか
日本語では「なぜ」の部分が調べられなかったので調べました。
海外のQAサイトに記載されていたので、翻訳を試みます。
引用元:
https://www.quora.com/Why-does-JavaScript-hoist-variables
#おおまかな理由
・関数において、定義が上で呼び出しが下だと読みづらいから(アンチMeta-Language)
・関数の相互呼び出しのため
→副作用によりvarの巻き上げが仕様になった
#詳細
以下、引用元のDan Shappir氏の回答を翻訳します。
First, it’s important to note that only variables declared using the var keyword are hoisted.
Variables declared using the newer let and const keywords are not hoisted.
Instead variables declared using them can only used after the point of declaration.
(They’re also block scoped, as opposed to var which is function scoped, but that’s a different discussion.)
まず大事なこととして、「var」を用いた宣言のみ巻き上げられ、「let」や「const」を用いたものは巻き上げられません。
それら(「let」や「const」)を用いて宣言した場合はそれ以降の行でしか使用できません。
(さらに言うならブロックスコープのみであり、「var」は関数スコープですが、それはまあ別の話です)
Brendan Eich, JavaScript’s creator had this to say on the topic of hoisting:
function declaration hoisting is for mutual recursion & generally to avoid painful bottom-up ML-like order - Twitter
var hoisting was an implementation artifact. - Twitter
JavaScriptの製作者であるBrendan Eich氏は、巻き上げについて下記のように述べました。
- 関数宣言の巻き上げは、相互呼び出しのためと、主にMLのような下から上への(耐え難い)呼び出し順序を回避するための、両方のために存在します。
- varの巻き上げは実装により生み出されたものです。
In other words, what happened was that JavaScript implemented hoisting of function declarations so that programmers would not be forced to place the inner-most functions at the top of the script block, and the outer-most (top-level) functions at the bottom.
This order, which is forced in ML languages (such as LISP) is painful because programmers prefer reading code top-to-bottom, rather than bottom-to-top.
Languages like C/C++ get around this issue by using header files, and standalone declarations, which JavaScript doesn’t have.
Also, hoisting was required for implementing mutual recursion.
言い換えると、プログラマーが内側の関数を上に定義し、外側の(内側の関数を呼び出す)関数を下に書かなくても済むようにしたということです。
この、ML言語(Lispのような)で強制される順序(内→外の順に上から書く)は耐え難いものでした。なぜならプログラマー達は下から読むより上から読む方を好むからです。
CやC++は、ヘッダファイルとスタンドアロン宣言を使用することでこの問題に対応しましたが、JavaScriptにはそれはありませんでした。
また、巻き上げは相互呼び出しの実装にも必要でした。
The hoisting of functions was implemented by having the JavaScript interpreter perform two passes over the code.
In the first pass declarations were extracted, and in the second pass the code was actually executed.
This resulted in the side-effect of also hoisting variable declarations to the top of their scope.
Thus, this behavior was an artifact of the implementation of the JavaScript interpreter, as Brendan Eich stated.
関数の巻き上げは、JavaScriptインタプリタが2つの段階を踏むようにすることで実装されました。
まず最初に、宣言部分が抜き出され、そしてその後にコードが実際に実行されるように。
この実装で、「変数」宣言もスコープの先頭に来るようになる、という副作用をもたらしました。
このようにして、Brendan Eich氏が述べたように、この動作がJavaScriptインタプリタの実装となりました。
Many programmers coming to JavaScript from languages such as C/C++, and Java, where variable declarations aren’t hoisted, did not like this behavior.
Thus let and const were introduced into the language as a part of ES6 in order to have it behave more like those other languages.
(The class mechanism was introduced for similar reasons.)
CやC++、Javaなどの変数宣言が巻き上げられない仕様の言語からJavaScriptに入ってきた多くのプログラマーはこの動作を好みませんでした。
上記のようなほかの言語と同様にふるまえるように、ES6の一部として「let」と「const」が登場しました。
(クラスもES6で登場しましたが、似たような理由によるものです)