Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
24
Help us understand the problem. What is going on with this article?
@jkr_2255

ES6時代の巻き上げ(hoisting)

More than 3 years have 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となります。

24
Help us understand the problem. What is going on with this article?
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
jkr_2255
qiitadon
Qiitadon(β)から生まれた Qiita ユーザー・コミュニティです。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
24
Help us understand the problem. What is going on with this article?