質問でベストプラクティスについて言及したので、将来あなたや他の人に役立つ可能性のあるいくつかのプラクティスを表示するために、コードをリファクタリングしました。このリファクタリングで使用される概念のリストを以下に示します。
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にはまだ定数 はありませんが、モジュール パターンのこの方法論は、予測可能な結果を伴う適切なソリューションを提供します。