Help us understand the problem. What is going on with this article?

ES6時代の巻き上げ(hoisting)

More than 1 year has passed since last update.

JavaScriptの直感的に理解しづらい挙動として、巻き上げ(hoisting)があります。しかも、ES6で加わったconstletは、従来と一味違った挙動を示します。

ES5での巻き上げ

ES5で宣言できるものとして、varによる変数の宣言と、functionによる関数宣言がありますが、この2つは巻き上げで挙動が違ってきます。

var

varは関数スコープですが、変数宣言だけ関数トップにあるものとして処理され、初期値の代入は元の位置で実行されます。

varの巻き上げの例
// 区別のために、同じ変数を外側でも宣言

var i = 7;

function foo(){
  // var i; はここにあるのと同じ扱いに

  console.log(i); // undefined

  var i = 'hello';
  console.log(i); // hello
}

console.log(i); // 7

foo();

function

functionで書き始める関数宣言の場合、スコープの中ならどこでも呼ぶことができます。varのような「名前だけあってundefined」ということにはなりません。もちろん、var f = function(){...};のような関数式の場合は、代入より前に呼ぶことはできません。

functionの巻き上げ
function test(){
  inner1(); // 呼べる
  inner2(); // 呼べない

  function inner1(){
    console.log('inner1');
  }
  var inner2 = function(){
    console.log('inner2');
  };
}

ES6では

ES6でも、従来のvarfunctionの挙動は変わりませんが、新しく加わったletconstは挙動が違ってきます(なお、どちらもスコープに関する挙動は同じです)。

これらはよく「巻き上げがない」と言われますが、(それを巻き上げと呼ぶかどうかは別として)宣言前の同一スコープにも影響します。では、先程のvarの例をletにしてみましょう。

varをletにしただけ
// 外側はvarでもletでも同じだけど、気分的に
let i = 7;

function foo(){

  console.log(i); // さあ、どうなる?

  let i = 'hello';
  console.log(i); // hello
}

console.log(i); // 7

foo();

「さあ、どうなる?」の部分は、letの宣言が上に影響しないなら、外側の7になると思うかもしれませんが、実際にはReferenceErrorとなってしまいます。このように、代入前にletconstの変数をアクセスしてReferenceErrorとなるのは、Temporal Dead Zoneと呼ばれます(MDN)。なお、本来エラーになるものだからか、Babelで正確にコンパイルされないこともあるようなので、お気をつけください。

あと、あくまでReferenceErrorとなるかは「代入と参照のコードの実行タイミング」によるもので、「コードの記載位置」とは別物です。少し前に @raccy さんの記事でのやり取りで知った話ですが、

const f = () => {
  console.log("call f");
  g(); // 後から定義する関数を書いても問題が無い。
};
const g = () => {
  console.log("call g");
};
// main
f(); // 最後に実行する。

のように、あとから定義される変数を参照しても、宣言が実行されてからしか呼ばれない関数の中にあるのであれば、特に問題はありません。逆に、function()の巻き上げを使うなどして、constより下に書いた関数をconstの実行前に呼べばReferenceErrorとなります。

jkr_2255
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした