web-dev-qa-db-ja.com

グローバル変数が悪いと聞きましたが、どのような代替ソリューションを使用する必要がありますか?

グローバル変数は悪い であり、代替手段を使用すべきであるという箇所をすべて読みました。特にJavaScriptでは、どのソリューションを選択する必要があります。

私は、2つの引数(function globalVariables(Variable,Value))が渡されると、変数がローカル配列に存在するかどうかを調べ、値がValueに設定されている場合はVariableおよびValueが追加されます。関数が引数なしで呼び出された場合(function globalVariables())、配列を返します。おそらく、関数が1つの引数(function globalVariables(Variable))だけで起動される場合、配列のVariableの値を返します。

どう思いますか?グローバル変数を使用するための代替ソリューションと引数を聞きたいです。

globalVariables();の使用方法

function append(){
    globalVariables("variable1","value1"); //globalVariables() would append variable1 to it's local array.
};

function retrieve(){
    var localVariable1 = globalVariables("variable1"); //globalVariables() would return "value1".
};

function retrieveAll(){
    var localVariable1 = globalVariables(); //globalVariables() would return the globalVariable()'s entire, local [persistently stored between calls] array.
};

function set(){
    globalVariables("variable1","value2"); //globalVariables() would set variable1 to "value2".
};

これは シングルトンパターン BTW?

この特定のシナリオでは、ある時点で関数が変数を設定し、ユーザーがフォームを送信した後で別の関数がその変数を取得する必要がある場合があります。したがって、最初の関数は、最初の関数から呼び出されることはないため、変数を引数として後の関数に渡すことができませんでした。

ありがとう、私はあなたのすべての助けに感謝します!

68
Jonathon Oates

Javascriptでグローバル変数が推奨されない主な理由は、javascriptではすべてのコードが単一のグローバル名前空間を共有しているため、javascriptがグローバル変数を暗示しているためです。ローカルスコープで明示的に宣言されていない変数は、自動的にグローバル名前空間に追加されます。グローバル変数に依存しすぎると、同じページ上のさまざまなスクリプトが衝突する可能性があります( Douglas Crockfordの記事 を読んでください)。

グローバル変数を減らす1つの方法は、 YUIモジュールパターン を使用することです。基本的な考え方は、モジュール外でアクセスする必要がある関数を含むオブジェクトを返す関数ですべてのコードをラップし、戻り値を単一のグローバル変数に割り当てることです。

_var FOO = (function() {
    var my_var = 10; //shared variable available only inside your module

    function bar() { // this function not available outside your module
        alert(my_var); // this function can access my_var
    }

    return {
        a_func: function() {
            alert(my_var); // this function can access my_var
        },
        b_func: function() {
            alert(my_var); // this function can also access my_var
        }
    };

})();
_

モジュール内の関数を他の場所で使用するには、FOO.a_func()を使用します。この方法でグローバル名前空間の競合を解決するには、FOOの名前を変更するだけです。

128
z33m

セマンティクス私の男の子。セマンティクス。

1つのグローバルから始めます:myApp = {};すべてがその中にあるべきです。唯一の例外はAJAXライブラリです(JSONPコールバックの操作のような極端な例外がいくつかあります)。

MyAppにはプロパティがほとんどありません。構成や設定などのコンテナにアプリケーションプロパティを保持する必要があります。

myApp = {
    config:{
        prop:1
    },
    settings:{
        prop:2
    },
    widgets:{
        List: function(props){},
        Item: function(props){}
    }
}

次に、下位のモジュール、コンポーネント、シングルトン、およびクラスコンストラクター(ウィジェット)により多くのプロパティを設定できます。

このセットアップは、myAppグローバルで取得できるため、他の場所から任意のプロパティにアクセスできるという追加の利点を提供します。ただし、検索は高速であるため、可能な場合は常に「this」を使用する必要があります。そして、プロパティを直接設定するだけで、疑似ゲッター/セッターなどに煩わされることはありません。ゲッター/セッターが本当に必要な場合は、その特定の用途に合わせてコーディングしてください。

あなたの例がうまくいかない理由は、それがあまりにも一般的であり、あなたがグローバル空間で働くための言い訳を探しているようだからです。

そして、プライベート変数で賢くならないでください。それらも悪い: http://clubajax.org/javascript-private-variables-are-evil/

40
mwilcox

グローバル状態は、いくつかの領域で問題を引き起こします。 1つはコードの再利用です。グローバルな状態にアクセスすると、コンポーネントはその環境(それ自体の外側の何か)を認識している必要があります。これは、コンポーネントを予測不能にするため、できるだけ避ける必要があります。

GlobalVariables関数にアクセスするオブジェクトがあり、別のページで使用したいとします。 globalVariablesオブジェクトを定義する方法、または定義する方法を知る方法はありますか?ただし、情報をコンストラクターに渡すか、関数の引数として渡すことができれば、オブジェクトに必要なものを簡単に判断できます。

また、グローバルスコープにアクセスまたは変更すると、他のオブジェクトに影響を与えるリスクがあります。これが、jqueryのようなライブラリがグローバルスコープで1つの名前のみを使用する理由です(可能な限り)。他のライブラリと競合する可能性を減らします。つまり、グローバルスコープは制御できないため、危険です。

9
Lee

グローバル変数の使用は、選択する言語に関係なく、一般的に悪い習慣です。 strict mode の場合、それらは(簡単に)使用することさえ許可されていません。

私が見つけた次のコードを検討してください。

if (typeof session != 'undefined' && !data.cart.request_status)
  data.input_definitions.passengers =
    inflate_passenger(session, data.input_definitions.passengers);

コード検索がどこに設定されているかがわからなかったので、私は振り向いてこのsession変数がどこから来たのかをプログラマーに尋ねる必要がありました。

会社から別のパッケージがグローバル変数を設定することが判明しました。コードは冗談のようなものです。説明する必要がある場合は、おそらくあまり良くありません。

ES6を使用した回避策:

Nodeでimportまたはrequireを使用して目的のものをレキシカルスコープに入れる場合、知らないうちに人々があなたのグローバル環境に触れないようにしてください。

import {Sesssion} from 'api-core';
const Session = require('api-core').session;

ブラウザにコードを配信するフロントエンドにいる場合、 Babel を使用してES6コードをトランスパイルしない限り、importを使用できません。

Gulp.jsを使用したトランスコンパイルの例:

// $ npm install --save-dev gulp-babel babel-preset-es2015

// gulpfile.js
const gulp  = require('gulp');
const babel = require('gulp-babel');

gulp.task('transpile', () => {
  return gulp.src('src/app.js')
    .pipe(babel({presets: ['es2015']}))
    .pipe(gulp.dest('dist'));
});

// $ gulp transpile

レガシー回避策:

ES6機能の使用がオプションではない場合、グローバル変数の束を使用する唯一の回避策は、1つのみを使用することであり、希望があります。

// scripts/app.js
var MyApp = {
  globals: {
    foo: "bar",
    fizz: "buzz"
  }
};
3
nicooga

あなたは本当にこれをしたくありません。
理由については、例えばここの一番上の投稿: 本番環境でこれまで見た中で最も悪かったコードは何ですか?

補足として、場所をグローバルで散らかすことなく、常に「グローバル」コードを実行できます。

(function () {
    var notaglobal = 1;
    alert(notaglobal);
})();
//notaglobal is not defined in this scope        
3
Andras Vass

ソリューションの問題は、グローバル変数の欠点をすべて残しながら、コードを理解しにくくすることです。リンクしたページが問題をカバーしています。提案されたソリューションが本当に解決する唯一の問題は名前空間の汚染ですが、宣言が関数呼び出しであるのと同じくらい簡単にどのグローバル変数が宣言されているかを見ることができません。

解決策は、グローバル変数なしでコードを書くことです。関数に値が必要な場合は、引数として渡します。

2
Yacoby

this 記事の言及として、他の答えは匿名関数で最も説明します。

匿名関数は、デバッグ、保守、テスト、または再利用が困難です。

以下は通常の機能の例です。読みやすく、理解しやすいです。

/* global variable example */

    var a= 3, b= 6;
    
    function fwithglobal(){
    console.log(a, b); // 3 6 expected
    }
    
    fwithglobal(); // first call
    
    function swithglobal(){
    var a=9;
    console.log(a, b); // not 3 6 but 9 6
    }
    
    swithglobal(); // second call
    

/* global variable alternative(function parameter) */

    function altern(){
    var a= 3, b= 6; // var keyword needed
      f_func(a,b);
      s_func(a,b);
    }
    
    function f_func(n, m){
    console.log(n, m); // 3 6 expected
    }
    
    function s_func(n, m){
    var a=9;
    console.log(n, m); // 3 6 expected
    }
    
    altern(); // only once
1
Guspan Tanadi
var ASHIVA_HandsOffNHS = (function() {
    
    // VARIABLES

    var my_var = 10;


    // PRIVATE FUNCTIONS
    
    function bar() {
        window.alert(my_var + 5);
    }


   // PUBLIC OBJECT

    myObject = {};
    
    myObject['a_func'] = function() {
            my_var += 10;
            window.alert(my_var);
        };
        
    myObject['b_func'] = function() {
            my_var = 0;
            window.alert(my_var);
        };

    return myObject;

})();

ASHIVA_HandsOffNHS.a_func();
ASHIVA_HandsOffNHS.b_func();
ASHIVA_HandsOffNHS.a_func();
1
Rounin

グローバル変数は、管理されないままにしておくと不良です!

グローバル変数の潜在的なリスクは、頻繁に使用されるオブジェクトをすぐに使用できることの喜びと生産性の向上と同じくらい高いです。

単一の代替案を探すべきではないと思います。代わりに、これらのグローバルの管理を担当する1つのオブジェクトを推奨し、コードベース/コンポーネントが成熟するにつれて、それらをリファクタリングします

私が重要だと思う現在の回答で言及されていないことの1つは、DIおよびIoCコンテナの理解です。これらは、人々がグローバル変数で解決しようとする多くの問題に対処しますが、オブジェクトライフサイクルなど、単純なグローバルではできない関連する懸念をカバーします。

0
SystematicFrank