36
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptAdvent Calendar 2017

Day 20

ES6時代の巻き上げ(hoisting)

Last updated at Posted at 2017-12-19

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となります。

36
27
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
27

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?