(旧)コードのスコープ
Topics
(2023/12/24) この文書の原文は削除されました。以後は「ブロック開発の基本原理」以下を参照ください。便宜上、しばらく訳文を掲載しますが、内容は更新されず、一部古くなっていますので注意してお読みください。
歴史的に、Web ページにロードされた JavaScript ファイルは同じスコープを共有します。つまり1つのファイルで宣言されたグローバル変数は他のファイルのコードからも参照できます。
この動きを見るために3つの JavaScript ファイルをロードする Web ページを作成します。最初の first.js
ファイルは以下です。
var pluginName = 'MyPlugin';
console.log( 'Plugin name is ', pluginName );
2つめの second.js
です。
var pluginName = 'DifferentPlugin';
console.log( 'Plugin name is ', pluginName );
そして最後の third.js
です。
console.log( 'Plugin name is ', pluginName );
同じページにロードされると first.js
と second.js
はそれぞれ内部で宣言したプラグイン名を表示します。そしてグローバル変数 pluginName
を、仮に値があっても上書きします。third.js
を実行してコンソールにどちらの値が表示されるかは不定です。出力は third.js
が実行されたときのグローバル変数 pluginName
の値によりますが、これはロードされたファイルの順番によります。
この動きは問題となります。これがコードにスコープを設定する理由です。コードにスコープを設定することで、各ファイルを他のファイルから分離し、値の期待しない変更を防止できます。
関数内でコードにスコープを設定する
JavaScript ではコードを関数内に書くことでスコープを設定できます。関数には関数のみで有効なスコープ「ローカルスコープ」があります。また JavaScript では名前のない関数「無名関数」を書くことで、グローバルスコープでの関数名の上書きを防止できます。
この JavaScript 機能を活用するには first.js
を以下のように書いてスコープを設定します。
function() {
var pluginName = 'MyPlugin';
console.log( 'Plugin name is ', pluginName );
}
second.js
です。
function() {
var pluginName = 'DifferentPlugin';
console.log( 'Plugin name is ', pluginName );
}
そして third.js
です。
function() {
console.log( 'Plugin name is ', pluginName );
}
このトリックによりファイルが他のファイルの変数を上書きすることはありません。ただし残念ながら期待どおりに動作しません。関数が誰からも呼び出されないためです。関数は 定義 しただけで、まだ 実行 していません。
無名関数の自動実行
JavaScript での無名関数の実行にはいくつかの方法がありますが、次の方法がもっとも人気があります。
( function() {
// コードをここに
} )( )
関数を括弧で囲み、他の名前付き関数のように呼び出します。このパターンは即時実行関数式 (Immediately-Invoked Function Expression)、あるいは IIFE と呼ばれます。
IIFE で書いた first.js
です。
( function() {
var pluginName = 'MyPlugin';
console.log( 'Plugin name is ', pluginName );
} )( )
second.js
です。
( function() {
var pluginName = 'DifferentPlugin';
console.log( 'Plugin name is ', pluginName );
} )( )
そして third.js
です。
( function() {
console.log( 'Plugin name is ', pluginName );
} )( )
first.js
と second.js
の中のコードはグローバルスコープの他の変数の影響を受けません。したがって安全で不変です。
一方、third.js
は変数 pluginName
を宣言しないため、提供する必要があります。IIFE でもグローバルスコープから変数を取得し、関数にわたすことができます。グローバル変数 window.pluginName
を使用して、次のように third.js
を書き換えます。
( function( name ) {
console.log( 'Plugin name is ', name );
} )( window.pluginName )
将来の変更
冒頭に次の文章がありました。
歴史的に、Web ページにロードされた JavaScript ファイルは同じスコープを共有します。
「歴史的」に注意してください。
JavaScript は誕生してから大きく進化してきました。2015 年にはファイルごとの個別のスコープを導入する「モジュール」あるいは「ES6 モジュール」をサポートしました。first.js
のグローバル変数は second.js
にエクスポーズされません。この機能はすでにモダンなブラウザーでサポートされていますが、すべてではありません。モジュールをサポートしないブラウザーで動作する必要があるのであれば、IIFE の使用が最後の砦です。
最終更新日: