2

重複の可能性:
JavaScript変数スコープ

私は(明らかに)Javascriptにかなり慣れていないので、グローバル変数とローカル変数の使用法について他のスレッドでいくつかの異なるポイントを見てきましたが、この主題に関するいくつかの基本的なポイントを1か所にまとめようとしています。

関数の外部で宣言された(または内部で使用された)次の違いは何ですか?

var things = 1;

もの=1;

varを使用すると、現在のスコープで変数が宣言されることを理解しています。したがって、varを省略すると、グローバルになります。現れる可能性のあるいくつかの落とし穴は何ですか?この場合、変数が互いに踏み合う可能性のある場所の簡単な例を誰かが挙げてもらえますか?

前もって感謝します。

4

3 に答える 3

2
  1. すでにグローバルスコープにいる場合は、違いが非常に小さいため、心配する必要はありません。

  2. 2つのforループがあり、それらを使って何かをしたいとします。

for (i = 0; i < elements.length; i++) {
    element = elements[i];
    for (i = 0; i < items.length) {
        item = items[i];
        element.add(item);
    }
}

この擬似コードは、多くの異なる言語で正常に機能します。プログラムは内部ループと外部ループを確認し、それiが同じものを参照していないことを認識できました。

JavaScriptでは、それらは同じiです。
これは、他の言語にはブロックスコープがあるためです。新しい中括弧を入力すると、プログラムは変数を新しいものとして扱います。

JavaScriptには関数スコープしかありません。つまり、関数内の変数はnewとして扱われますが、制御ステートメント(、、)内では、ifそれらは同じ値を持つ同じ変数です。 したがって、外側のループは0に設定されてから、内側のループに入ります。 内側のループはすべてのアイテムのリストを通過し、それが進むにつれて構築されます... 次に、外側のループに戻り、それでも等しい... それよりも小さい場合は、に1が追加され、現在はより高くなります。長さよりも大きいので、内側のループでは何も起こりません... ...代わりにより大きい場合、外側のループは1回の通過後に終了します。forswitch
i
i
iitems.length - 1
elements.lengthiitems
items.lengthelements.length

これで、プログラム全体で、または、または、または、または、または、または、などを数回(数x万行も)使用したい場合について考え始めることができると確信しています。同じ名前で2つの異なるものを呼び出そうとすると、問題が発生する可能性がある、上記のループのような状況について考え始めることができます。namevalueelsumidefaultsrcurlimgscript

これはvar-fallthroughと同じ問題です

と呼ばれる変数を使用する関数と、xと呼ばれる別の変数を使用する別の関数がある場合x、それは素晴らしいことです......変数を宣言するのを忘れない限り。

// no problems!
function func1 () { var x = 0; }
function func2 () { var x = "Bob"; }

// big problems!
function func1 () { x = 0; }
function func2 () { x = "Bob"; }

func1セットwindow.x = 0; func2セットwindow.x = "Bob";

... window.x42に等しいと想定されていた場合、他のプログラムが正しく機能するためには、いくつかの欠落しているために、3つの壊れたアプリが存在する可能性がありますvar

ただし、グローバル変数を即座に設定するわけではありません。それが実際に行うことは、機能チェーンを通過することです。別の関数内に関数を作成すると、宣言されていない変数はその親の変数、次に祖父母の変数、次に曽祖父母の変数を調べます...
それが完全に到達しwindow、誰もその変数を持っていない場合名前を入力すると、その名前の名前がに作成されwindowます。

function func1 () {
    var x = 0;

    function func2 () {
        var y = 1;
        x = 2;
        z = 3;
    }

    func2();
}

func1を呼び出すと、それ自体xが0に設定され、func2が呼び出されます。func2は自身yを1に設定し、次にfunc1xを2に設定します。次に、func2にはないz、func1にはないzwindowないためz、3に設定window.zします。

これは混乱の始まりに過ぎず、その関数内(およびその関数内で作成された関数)で使用可能である必要がある変数を定義していることを確認するのは非常に良い考えです。 ..そして、既存の変数を参照するときは、それらを注意深く参照し、コード内でその変数がどこにあるべきかを知っています(どの関数がそれを定義したのか... ...チェーンのどこにプログラムが行くのか) )に到達する前に、見るのをやめてwindowください。また、別の関数の内部から変更する理由を説明してください。

于 2012-10-09T18:27:04.810 に答える
1

一般的な落とし穴はループカウンターです。これらは常に名前が付けられi、衝突します。例:

function a() {
    for (i = 0; i < 5; i++)
        b();
}
function b() {
    for (i = 0; i < 3; i++)
        ; // something
    // now, the /global/ i is reset to 3
    // … and the condition in function a will never be met
}
// so
a();
// is an infine loop instead of executing something 15 times
于 2012-10-09T17:49:52.753 に答える
0

多くのCスタイルの言語とは異なり、JavaScriptはブロック構文をサポートしていますが、ブロックスコープをサポートしていないため、以下は期待どおりに実行されない場合があります。

var foo = 'bar';

{
  var foo = 'baz';
}

console.log(foo); // 'baz'

これは、次のようなブロックをサポートする他のJavaScript構造でも明らかですif

var foo = 'bar';

if (true) {
  var foo = 'baz';
}

console.log(foo); // 'baz'

さらに、Bergiが指摘したように、aは新しいスコープを作成しないため、sのiカウンターはfor相互にオーバーライドします。for

Crockfordは、JavaScriptのブロックスコープの欠如を言語の「ひどい部分」と見なしています。代わりに、JavaScriptには字句スコープがあるため、関数のみが新しいスコープを作成します。

var foo = 'bar';

(function() {
  var foo = 'baz';
  console.log(foo); // 'baz'
}());

console.log(foo); // 'bar'

JavaScriptのすべての関数は、それを含む関数の変数にアクセスできます。内側は外側にアクセスできますが、その逆はできません。上記の例の場合、IIFE(即時呼び出し関数式)はfoo = 'bar';グローバルスコープで定義されたものにアクセスできますが、代わりにfooローカルvar宣言でオーバーライドして、に等しく設定し'baz'ます。

ボーナスポイント:Shog9は、with次のようなオブジェクトリテラルを使用してブロックスコープをシミュレートできることを発見しました。

var foo = 'bar';

with ({foo: 'baz'}) {
  console.log(foo); // 'baz'
}

console.log(foo); // 'bar'

Crockfordはそのあいまいさのために落胆withしますが、ブロックスコープが本当に必要な場合は、回避策に害はないと思いますwith

于 2012-10-09T18:18:14.657 に答える