次のコードでは、関数を宣言し、その後に関数と同じ名前の変数を宣言しています。
function a(x) {
return x * 2;
}
var a;
alert(a);
これはundefined
に警告することを期待していましたが、実行すると、警告に次のように表示されます。
関数a(x) {
return x * 2
}
変数に値を割り当てた場合(var a = 4
など)、アラートにはその値(4
)が表示されますが、この変更がない場合、a
は関数として認識されます。
なんでこんなことが起こっているの?
関数はオブジェクトのタイプです値のタイプです。
値は変数(およびプロパティ、および関数への引数など)に保存できます。
関数宣言:
A var
ステートメント:
宣言とvar
ステートメントの両方が巻き上げられます。そのうちの1つだけが変数a
に値を割り当てます。
JavaScriptでは、関数宣言と変数宣言の両方が、関数で定義されている場合は関数の最上部に、関数の外ではグローバルコンテキストの最上部に引き上げられます。また、関数宣言は変数宣言よりも優先されます(変数割り当てよりも優先されません)。
巻き上げ時に関数宣言が変数宣言をオーバーライドする
まず、変数を宣言します。
_var a; // value of a is undefined
_
次に、a
の値は関数です。関数の宣言は変数の宣言よりも優先されます(変数の代入よりは優先されません)。
_function a(x) {
return x * 2;
}
_
そして、それがalert(a);
を呼び出すときに得られるものです。
ただし、変数を宣言する代わりに変数の割り当てを行う場合、_var a = 4;
_が割り当てられた値_4
_が優先されます。
変数名として関数名を使用すると、その値は関数本体に置き換えられます。したがって、「var a」は関数「a」の本体になり、アラートには関数「a」が表示されます。
また、var a
は巻き上げられており、このようになっています
var a; // placed
function a(x) {
return x * 2;
};
var a; // removed
alert (a); // a is replaced by function body
var a
は巻き上げられるので、4 to a
:
var a; // placed
function a(x) {
return x * 2;
};
var a = 4; // removed
a = 4 // added
alert (a); // a is now 4
ES6には、let
の代わりにconst
/var
を使用するときにSyntaxError: Identifier (?) has already been declared
を定義することにより、より優れたソリューションが付属しています。
let
function foo () {}
let foo;
// => SyntaxError: Identifier 'foo' has already been declared
const
function foo () {}
const foo = 1;
// => SyntaxError: Identifier 'foo' has already been declared
ご了承ください const foo;
動作しません。 SyntaxError: Missing initializer in const declaration