web-dev-qa-db-ja.com

varキーワードなしで変数を宣言する

W3schoolsには次のように書かれています:

「var」を使用せずに変数を宣言すると、変数は常にGLOBALになります。

関数内でグローバル変数を宣言すると便利ですか?いくつかのイベントハンドラーでいくつかのグローバル変数を宣言することを想像できますが、それは何に適していますか? RAMのより良い使用法?

49
xralf

いいえ、RAMのメリットなどはありません。

W3schoolsが話していることは、私が The Horror of Implicit Globals と呼ぶものです。次の機能を検討してください。

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;
    return variable1 + variable2;
}

簡単そうに思えますが、11行のタイプミスのため、varaible2 = 6;ではなくNaNを返します。そして、タイプミスの名前でグローバル変数を作成します。

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;
    return variable1 + variable2;
}
console.log(foo());     // NaN
console.log(varaible2); // 6?!?!?!

これは、関数がvaraible2(タイプミスに注意)に割り当てますが、varaible2はどこにも宣言されていないためです。 JavaScriptのスコープチェーンの仕組みにより、これはグローバルオブジェクト(アクセス可能な)の(新しい)プロパティへの暗黙的な割り当てになりますブラウザではwindowとして)。

それは単なるルーズモードJavaScriptの「機能」であり、完全に宣言されていない識別子への割り当てはエラーではありません。代わりに、グローバルオブジェクトに適切に作成し、グローバルオブジェクトのプロパティはグローバル変数です。 (ES5まで、すべてのグローバルはグローバルオブジェクトのプロパティでした。ES2015の時点で、グローバルオブジェクトのプロパティではない新しい種類のグローバルが追加されました。グローバルスコープletconst、およびclassは、新しい種類のグローバルを作成します。

私の例はタイプミスですが、もちろん、必要に応じて意図的に行うこともできます。結局のところ、それは言語の明確に定義された部分です。そう:

myNewGlobal = 42;

... myNewGlobalが宣言されていない場所は、新しいグローバルを作成します。

しかし、意図的にそれを行わないことを強くお勧めします。コードの読み取りと保守が難しくなり、コードがより一般的かつ広範囲になったときにJavaScriptモジュールと互換性がなくなります。実行時に関数内からグローバル変数を本当に作成する必要がある場合(既に赤いフラグですが、正当な理由があります)、window(または参照するもの)のプロパティに割り当てて明示的に作成します。あなたの環境のグローバルオブジェクト;それはブラウザのwindowです):

window.myNewGlobal = 42;

実際、ES5の strict mode を使用することをお勧めします。厳密モードは、暗黙的にグローバルを作成するのではなく、宣言されていない識別子にエラーを割り当てます。ストリクトモードを使用していた場合、上記のfooの問題は診断がはるかに簡単でした。

"use strict"; // Turns on strict mode for this compilation unit

function foo() {
    var variable1, variable2;

    variable1 = 5;
    varaible2 = 6;                 // <=== ReferenceError
    return variable1 + variable2;
}
console.log(foo());

やや接線ですが、一般的には可能な限りグローバルを避けることをお勧めします。グローバル名前空間は、すでに非常に多くのブラウザで散らかっています。ブラウザはidを持つDOM内のすべての要素に対して、nameを持つほとんどの要素に対してグローバルを作成し、独自のいくつかの事前定義済みグローバル(titleなど)を持ちます。コードと簡単に競合する可能性があります。

代わりに、Niceスコーピング関数を自分で定義して、シンボルを入れてください:

(function() {
    var your, symbols, here, if_they_need, to_be_shared, amongst_functions;

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

そして、それを行う場合、ストリクトモードを有効にすることができます。

(function() {
    "use strict";
    var your, symbols, here, if_they_need, to_be_shared, amongst_functions;

    function doSomething() {
    }

    function doSomethingElse() {
    }
})();

...これは、前述のように、宣言されていない識別子への割り当てをエラーに変換するという利点があります( さまざまなその他の有用なもの とともに)。

JvaScriptmodule(ES2015で追加されましたが、今ではワイルドになり始めています)では、厳格モードがデフォルトで有効になっていることに注意してください。 (これはclass定義にも当てはまります。これもES2015の新機能です。)

84
T.J. Crowder

varを忘れた場合の副作用

暗黙のグローバルと明示的に定義されたグローバルとの間にはわずかな違いがあります。違いは、delete演算子を使用してこれらの変数を未定義にする機能にあります。

•varで作成されたグローバル(関数の外部でプログラムで作成されたグローバル)は削除できません。

•varなしで作成された暗黙のグローバル(関数内で作成されたかどうかに関係なく)は削除できます。

これは、暗黙のグローバルは技術的には実際の変数ではないが、グローバルオブジェクトのプロパティであることを示しています。プロパティはdelete演算子で削除できますが、変数は次のことができません。

// define three globals
var global_var = 1;
global_novar = 2; // antipattern
(function () {
   global_fromfunc = 3; // antipattern
}());
// attempt to delete
delete global_var; // false
delete global_novar; // true
delete global_fromfunc; // true
// test the deletion
typeof global_var; // "number"
typeof global_novar; // "undefined"
typeof global_fromfunc; // "undefined"

ES5 strictモードでは、宣言されていない変数(前述のスニペットの2つのアンチパターンなど)への割り当てはエラーをスローします。

JavaScriptパターン、Stoyan Stefanov(O’Reilly)。 Copyright 2010 Yahoo !, Inc.、9780596806750。

17
user278064

グローバル変数を使用するのは、グローバルにアクセスする必要がある場合のみです。その場合、関数の外側でvarキーワードを使用して宣言し、本当にグローバル変数を作成したいことを明確にし、宣言しようとするときにvarを忘れないようにします。ローカル変数。

一般に、グローバルスコープで必要なものができるだけ少なくなるように、コードのスコープを設定する必要があります。スクリプトで使用するグローバル変数が多いほど、別のスクリプトと一緒に使用できる可能性は低くなります。

通常、関数内の変数はローカルであるため、関数を終了すると消えます。

3
Guffa

関数内にグローバルにアクセス可能な新しいプロパティを作成すると、ウィンドウオブジェクトを参照することで簡単にアクセスできる場合があります(グローバルに宣言されたすべてのプロパティはウィンドウオブジェクトにアタッチされます)。

しかし、通常は何かをグローバルにアクセスできるように宣言すると、それらのプロパティが簡単に上書きされるなどの理由で、後で問題が発生する可能性があります。

2
brezanac

主な問題は、他の誰かがすでに同じ名前のグローバルを使用している可能性があることです。

次に、グローバルの値を変更すると、それらの値が上書きされます。

後でグローバルが次に使用されるときに、神秘的に変更されます。

2
QuentinUK

Var、let、またはconstを使用せずに関数内で変数を宣言することは、var、let、またはconstを使用して変数を宣言することよりも、関数内で有用ではありません。また、この質問に対する以前の回答で述べたように、関数ローカルで暗黙的なグローバル宣言は、宣言された関数の範囲外で混乱し、問題を引き起こす可能性があります。

W3schoolsの引用文と、この質問に対する以前の回答から欠落している微妙な点についてお話ししたいと思います。

まず、暗黙のグローバルを生成する関数を呼び出さない場合、暗黙のグローバルは生成されません。これは、声明の「常に」セクションに反するため、w3schoolsの引用とは微妙に異なります。

function generateImplicitGlobals(){
  x = "x";
  window.y = "y";
}

// before calling the generateImplicitGlobals function, we can safely see that the x and y properties of the window object are both undefined:
console.log("before calling the generateImplicitGlobals function, properties x and y of the window object are: " + window.x + " and " + window.y);

// before calling the generateImplicitGlobals function, we can test for the existence of global variables x and y; note that we get errors instead of undefined for both.
try{
  console.log("before calling the generateImplicitGlobals function, x is: " + x);
}
catch(e){
  console.log("before calling the generateImplicitGlobals function, an attempt to reference some global variable x produces " + e);
}

try{
  console.log("before calling the generateImplicitGlobals function, y is: " + y);
}
catch(e){
  console.log("before calling the generateImplicitGlobals function, an attempt to reference the global variable b also produces " + e);
}

以前の回答の微妙な点については、generateImplicitGlobals関数が呼び出されると、window.xプロパティまたはグローバル変数xにアクセスしようとすると同じ値が返されることがわかります(また、window.yプロパティとグローバルy変数は同じ値)。 generateImplicitGlobals関数の内部または外部から呼び出された場合、これらのステートメントは真です。

function generateImplicitGlobals(){
  x = "x";
  window.y = "y";
  console.log("inside the function, x and window.x are: " + x + " and " + window.x);
  console.log("inside the function, y and window.y are: " + y + " and " + window.y);
}

// now, call the generator, and see what happens locally and globally.
generateImplicitGlobals();
console.log("after calling the generateImplicitGlobals function, x, window.x, y, and window.y are: " + x + ", " + window.x + ", " + y + ", and " + window.y);
1
Ed_Johnsen

それはあなたのセキュリティとコードの安定性さえ傷つけるかもしれないと言うでしょう。

上で述べたように、変数のつづりを間違えるだけで間違いを犯す可能性があり、その解決策はキーワード"use strict";
このキーワードを宣言すると、エラーがスローされます:Uncaught ReferenceError: foo is not defined

また、セキュリティで保護されたコードも参照します。
1。セキュリティで保護されたコードを記述するとき、変数が実際に宣言された場所以外の場所にアクセスすることは望ましくありません。必要なくグローバル変数を宣言しないでください。
2。警告は常に注意深く読んで解決してください。つかいます "use strict";、JSlint、およびコードを改善するための警告を表示および解決するその他のツール。

0
Erik Rybalkin