Javascript / ECMAScriptの関数のスコープは何ですか?
-
04-07-2019 - |
質問
今日、Javascriptのネストされた関数について同僚と議論しました:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
この例では、cがそうであるように、bがaの本体の外側に到達できないことが試行によって指摘されています。ただし、dは-()の実行後です。 ECMAScript v。でこの動作の正確な定義を探します。 3標準、探している正確な文言が見つかりませんでした。 Sec.13 p.71が言っていないのは、関数宣言ステートメントによって作成された関数オブジェクトがどのオブジェクトにバインドされるかということです。何か不足していますか?
解決
これは静的スコープです。関数内のステートメントは、その関数内でスコープされます。
Javascriptには奇妙な振る舞いがありますが、これは var キーワードがなければ、グローバル変数を暗示しています。それはあなたのテストで見ているものです。あなたの「d」変数は、関数の本体内に記述されているにもかかわらず、暗黙のグローバルであるため利用可能です。
また、質問の2番目の部分に答えるには、関数は、変数のように、宣言されたスコープ内に存在します。
補足: グローバル変数、特に暗黙の変数は必要ありません。混乱を防ぎ、すべてをきれいに保つために、常にvarキーワードを使用することをお勧めします。
補足: ECMA標準は、Javascriptに関する回答を見つけるのにおそらく最も役立つ場所ではありませんが、悪いリソースではありません。ブラウザのjavascriptはその標準の単なる実装であることに注意してください。そのため、標準ドキュメントには、javascriptエンジンが構築されたときに(ほとんど)実装者が従うルールが示されます。関心のある実装、つまり主要なブラウザに関する特定の情報を提供することはできません。特に、主要なブラウザのjavascript実装の動作に関する非常に直接的な情報を提供する書籍が数冊あります。違いを説明するために、ECMAScript仕様とJavascriptに関する本の両方からの抜粋を以下に示します。この本がより直接的な答えを与えることに同意すると思います。
ECMAScript言語仕様の内容:
10.2 実行コンテキストの入力
すべての関数とコンストラクターの呼び出し 新しい実行コンテキストに入ります 関数がそれ自体を呼び出している場合 再帰的に。すべての戻り値が終了し、 実行コンテキスト。スローされた例外、 キャッチされない場合、1つを終了するか、 より多くの実行コンテキスト。
制御時 実行コンテキスト、スコープに入る チェーンが作成および初期化され、 変数のインスタンス化が実行され、 この値が決定されます。
スコープチェーンの初期化、 変数のインスタンス化、および この値の決定は依存します 入力されるコードのタイプ。
O'Reillyの Javascript:The Definitive Guide(第5版) :
8.8.1字句スコープ
JavaScriptの関数は字句的に 動的スコープではなく。この は、次のスコープで実行されることを意味します それらはスコープではなく定義されています 実行元。とき 関数が定義され、現在のスコープ チェーンは保存され、の一部になります 関数の内部状態。 ...
これらの種類の質問をカバーするために強く推奨されるのは、ダグラス・クロックフォードの本です。
JavaScript、The Good Parts http://oreilly.com/catalog/covers/9780596517748_cat.gif
Javascript、The Good Parts 、Oからも「ライリー。
他のヒント
私が理解しているように、これらはスコープに関する限り同等です:
function a() { ... }
and
var a = function() { ... }
dは「グローバル」として作成されていますが、実際にはウィンドウオブジェクトのプロパティとして作成されていることに注意してください。これは、ウィンドウオブジェクトに既に存在するものを誤って上書きしてしまう可能性があること、または変数が実際にまったく作成されない可能性があることを意味します。だから:
function a() {
d = 'Hello World';
}
alert(window.d); // shows 'Hello World'
ただし、できません:
function a() {
document = 'something';
}
window.documentオブジェクトを上書きできないため。
すべての実用的な目的のために、すべてのコードが巨大な with(window)
ブロックで実行されていることをイメージングできます。
Javascriptには2つのスコープがあります。グローバルで機能的。 " var"を使用して関数内で変数を宣言する場合キーワード、それはその関数、および任意の内部関数に対してローカルになります。関数の外部で変数を宣言する場合、グローバルスコープがあります。
最後に、変数を最初に宣言するときにvarキーワードを省略すると、javascriptは、宣言する場所に関係なく、グローバル変数が必要であると想定します。
つまり、関数aを呼び出しており、関数aはグローバル変数dを宣言しています。
...
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
d = 'Bound to global object.'
}
var が前に付かない場合、dはグローバルです。これを実行してdをプライベートにします:
function a() {
function b() {
alert('boo')
}
var c = 'Bound to local call object.'
var d = 'Bound to local object.'
}