スコープとかevalのメモ

var x=0;
(function(){
  x=1;
  var x=2;
  console.log(x); //2
})();
console.log(x); //0

グローバルとローカルにxという同名の変数が扱われているとして、ポイントは無名関数内の最初のx=1の代入部分、そして、その下のvar宣言。
var宣言は、どこにあろうともその直近スコープのトップレベルで宣言されたものとしてみなされる、という性質がある。
つまり処理の流れで書き直すとこうなる。

var x=0;
(function(){
  var x;
  x=1;
  x=2;
  console.log(x); //2
})();
console.log(x); //0

最初のコードでは、あたかもx=1はグローバルのxに代入しているように見えるが、
var文が先行され、スコープチェインでローカルのxにスコープが当たっている。
さらにvarと同時にx=2で初期化をしているつもりだが、あくまで宣言だけされた後で逐次的にx=1;x=2;と処理されるため、x=2の初期化のあとでx=1に上書きされるということにはならない。
※「変数値」はいったんundefindで定義されてから、コードの実行順で処理される。


evalすると

var x=0;
(function(){
  x=1;
  eval("var x=2;");
  console.log(x); //2
})();
console.log(x); //1

見事に結果が変わってしまう。
関数内のx=1では、この時点でローカルスコープ内のxが存在せず、スコープチェインを辿ってグローバルを参照しそこを上書きする。
evalによってローカル変数は直後にダイナミックに宣言され、その直前のx=1には干渉していない。

とりあえずまとめ

・通常変数宣言は、スコープのトップレベルで宣言したものとみなされる。
・evalしたvar文は、実行コンテキスト中で変数宣言の割り込みが可能になる。