1

以下のように、ローカル ストレージに保存され、ユーザー プロンプトで追加される単純なハイ スコア配列を作成しました。

それ自体が独立したファイルとして機能します。または、少なくともそのようです。

ただし、これをより大きなアプリケーションに統合しようとすると、グローバル変数 allScores でスコープの問題が発生しているようです。配列の長さは 0 のままです。変数の重複があるかどうかを確認しましたが、ありません。

関数の巻き上げとスコープについて読み込もうとしています。以下のコードが独立したファイルとして機能する理由はよくわかりませんが、それをより大きなアプリケーションに統合すると、スコープの問題が発生します。

これを別の方法で行うにはどうすればよいですか?私は JavaScript を初めて使用するので、私のベスト プラクティスはおそらく間違っています。ご指導をよろしくお願いいたします。ありがとう。

var allScores = [];

function saveScore() {

if (allScores.length === 0) {
    allScores[0]= prompt('enter score', '');
    localStorage ['allScores'] = JSON.stringify(allScores);
}

else if (allScores.length < 3) {
    var storedScores = JSON.parse(localStorage ['allScores']);
    storedScores = allScores;
    var injectScore = prompt('enter score', '');
    allScores.push(injectScore);
    allScores.sort(function(a, b) {return b-a});
    localStorage ['allScores'] = JSON.stringify(allScores);
}

else {
    var storedScores = JSON.parse(localStorage ['allScores']);
    storedScores = allScores;
    var injectScore = prompt('enter score', '');
    allScores.pop();
    allScores.push(injectScore);
    allScores.sort(function(a, b) {return b-a});
    localStorage ['allScores'] = JSON.stringify(allScores);
}
document.getElementById('readScores').innerHTML = allScores;
}**
4

3 に答える 3

1

質問でベストプラクティスについて言及したので、将来あなたや他の人に役立つ可能性のあるいくつかのプラクティスを表示するために、コードをリファクタリングしました。このリファクタリングで使用される概念のリストを以下に示します。

var saveScore = (function () { /* Begin IIFE */
    /*
    The variables here are scoped to this function only.
    They are essentially private properties.
    */
    var MAX_ENTRIES = 3;

    /*
    Move the sorting function out of the scope of saveScore,
    since it does not need any of the variables inside,
    and possibly prevent a closure from being created every time
    that saveScore is executed, depending upon your interpreter.
    */
    function sorter(a, b) {
        return b - a;
    }

    /*
    As far as your example code shows, you don't appear to need the
    allScores variable around all the time, since you persist it
    to localStorage, so we have this loadScore function which
    pulls it from storage or returns a blank array.
    */
    function getScores() {
        var scores = localStorage.getItem('scores');
        return scores ? JSON.parse(scores) : [];
        /*
        Please note that JSON.parse *could* throw if "scores" is invalid JSON.
        This should only happen if a user alters their localStorage.
        */
    }

    function saveScore(score) {
        /* Implicitly load the scores from localStorage, if available. */
        var scores = getScores();

        /*
        Coerce the score into a number, if it isn't one already.
        There are a few ways of doing this, among them, Number(),
        parseInt(), and parseFloat(), each with their own behaviors.

        Using Number() will return NaN if the score does not explicitly
        conform to a textually-represented numeral.
        I.e., "300pt" is invalid.

        You could use parseInt(score, 10) to accept patterns
        such as "300pt" but not anything with
        leading non-numeric characters.
        */
        score = Number(score);

        /* If the score did not conform to specifications ... */
        if (isNaN(score)) {
            /*
            You could throw an error here or return false to indicate
            invalid input, depending on how critical the error may be
            and how it will be handled by the rest of the program.

            If this function will accept user input,
            it would be best to return a true or false value,
            but if a non-numeric value is a big problem in your
            program, an exception may be more appropriate.
            */

            // throw new Error('Score input was not a number.');
            // return false;
        }

        scores.push(score);
        scores.sort(sorter);

        /*
        From your code, it looks like you don't want more than 3 scores
        recorded, so we simplify the conditional here and move
        "magic numbers" to the header of the IIFE.
        */
        if (scores.length >= MAX_ENTRIES) {
            scores.length = MAX_ENTRIES;
        }
        /* Limiting an array is as simple as decreasing its length. */

        /* Save the scores at the end. */
        localStorage.setItem('scores', JSON.stringify(scores));

        /* Return true here, if you are using that style of error detection. */
        // return true;
    }

    /* Provide this inner function to the outer scope. */
    return saveScore;

}()); /* End IIFE */

/* Usage */
saveScore(prompt('Enter score.', ''));

ご覧のとおり、スコア処理ロジックがこの関数コンテキスト内にカプセル化されているため、インターフェイスを使用せずに実質的に内部を改ざんすることはできません。理論的には、saveScore関数は他のコードに取って代わられる可能性がありますが、IIFEのコンテキストの内部は、アクセスできるものにのみ変更可能です。標準化されたECMAScriptにはまだ定数 はありませんが、モジュール パターンのこの方法論は、予測可能な結果を​​伴う適切なソリューションを提供します。

于 2013-01-16T04:50:55.650 に答える
1

JS クロージャーについて考えたことはありますか? ここにあなたにアイデアを与えるためのいくつかの部分があります..

var scoreboard = (function () {
    var _privateVar = "some value"; //this is never exposed globally
    var _allScores = [];

    return {
        getAllScores: function() { //public
            return _allScores;
        },
        saveScore: function(value) { //public
            _allScores.push(value);
        }
    };
})();

alert(scoreboard.getAllScores().length); //0
scoreboard.saveScore(1);
alert(scoreboard.getAllScores().length); //1
alert(scoreboard._privateVar); //undefined
alert(scoreboard._allScores); //undefined

このようにして、変数と関数が window オブジェクトに公開されることはなく、重複やスコープについて心配する必要はありません。一意である必要がある唯一の変数は、クロージャ関数の名前です (scoreboardこの例の場合)。

于 2013-01-16T03:52:59.700 に答える
0

環境にアクセスできなくても、Firefox 開発ツールを使用して (または firebug を入手して)、saveScore関数にブレークポイントを設定するのが最善の方法です。行ごとにステップ実行して値を確認し、コンソール ウィンドウ (REPL) で現在のスコープ内の式を評価することもできます。

https://developer.mozilla.org/en-US/docs/Tools/Debugger - Firefox を使用

http://getfirebug.com/javascript - firebug (firefox プラグイン) を使用

Web 開発を行っている場合、これらは非常に貴重なリソースです。そのため、その使用方法を学ぶために時間を投資してください。

于 2013-01-16T03:19:42.447 に答える